Project

General

Profile

Patch #42521 » 0002-Add-JavaScript-test-environment-And-dialog-controlle.patch

Takashi Kato, 2025-04-06 10:30

View differences:

Gemfile
94 94

  
95 95
group :development, :test do
96 96
  gem 'debug'
97
  gem 'importmap_mocha-rails'
97 98
end
98 99

  
99 100
group :development do
config/application.rb
109 109
    if File.exist?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
110 110
      instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
111 111
    end
112

  
113
    if Rails.env.local?
114
      config.importmap_mocha_style = 'tdd'
115
    end
112 116
  end
113 117
end
test/javascripts/controllers/dialog_controller.test.js
1
/**
2
 * Redmine - project management software
3
 * Copyright (C) 2006-  Jean-Philippe Lang
4
 * This code is released under the GNU General Public License.
5
 */
6

  
7
import { Application } from "@hotwired/stimulus"
8
import DialogController from 'controllers/dialog_controller'
9
import { assert } from 'chai'
10

  
11
const html = `
12
  <div data-controller="dialog" id="dialog">
13
    <div data-action="pointerdown->dialog#start pointerup->dialog#end pointercancel->dialog#end  pointermove->dialog#move touchstart->dialog#noop dragstart->dialog#noop" data-dialog-target="handler" id="handler">Drag Here</div>
14
    <div id="hide">Close</div>
15
  </div>
16
  <div id="wrapper"></div>
17
  <div id="modal-backdrop"></div>`
18

  
19
suite('dialog controller', () => {
20

  
21
  let container;
22
  let controller;
23

  
24
  setup(async () => {
25
    container = document.getElementById('container')
26
    const app = Application.start(container);
27
    await app.register('dialog', DialogController);
28

  
29
    container.insertAdjacentHTML('afterbegin', html)
30
  });
31

  
32
  teardown(() => {
33
    const clone = container.cloneNode(false);
34
    container.parentNode.replaceChild(clone, container);
35
  });
36

  
37
  test('connect lifecycle method', () => {
38
    const dialog = document.getElementById('dialog');
39
    controller = dialog.dialog_controller;
40
    assert.isNotNull(controller);
41
    assert.isNull(controller.dragging);
42
    assert.isNull(controller.backdrop);
43
  });
44

  
45
  test('start dragging', async () => {
46
    const handler = document.getElementById('handler');
47
    const dialog = document.getElementById('dialog');
48
    controller = dialog.dialog_controller;
49

  
50
    const event = new PointerEvent('pointerdown', { button: 0, clientX: 100, clientY: 100 });
51
    await handler.dispatchEvent(event);
52

  
53
    assert.isNotNull(controller.dragging);
54
    assert.isDefined(controller.dragging.dx);
55
    assert.isDefined(controller.dragging.dy);
56
    assert.isTrue(handler.classList.contains("dragging"));
57
  })
58

  
59
  test('move dialog', async () => {
60
    const handler = document.getElementById('handler');
61
    const dialog = document.getElementById('dialog');
62
    controller = dialog.dialog_controller;
63

  
64
    let event = new PointerEvent('pointerdown', { button: 0, clientX: 100, clientY: 100 });
65
    await handler.dispatchEvent(event);
66

  
67
    event = new PointerEvent("pointermove", { clientX: 150, clientY: 150 });
68
    await handler.dispatchEvent(event);
69

  
70
    const pos = controller.pos;
71
    assert.isDefined(pos.x);
72
    assert.isDefined(pos.y);
73
    assert.notEqual(pos.x, 0);
74
    assert.notEqual(pos.y, 0);
75
  })
76

  
77
  test('end dragging', async () => {
78
    const handler = document.getElementById('handler');
79
    const dialog = document.getElementById('dialog');
80
    controller = dialog.dialog_controller;
81

  
82
    let event = new PointerEvent('pointerdown', { button: 0, clientX: 100, clientY: 100 });
83
    await handler.dispatchEvent(event);
84

  
85
    event = new PointerEvent("pointerup");
86
    await handler.dispatchEvent(event);
87

  
88
    assert.isNull(controller.dragging);
89
    assert.isFalse(handler.classList.contains("dragging"));
90
  });
91

  
92
  test('show dialog', async () => {
93
    const dialog = document.getElementById('dialog');
94
    controller = dialog.dialog_controller;
95
    controller.show({ width: "500px", backdrop: "modal-backdrop" });
96
    const backdrop = document.getElementById("modal-backdrop");
97

  
98
    assert.equal(dialog.style.display, "");
99
    assert.equal(dialog.style.width, "500px");
100
    assert.isTrue(backdrop.classList.contains("modal-backdrop-open"));
101
  })
102

  
103
  test('hide dialog', () => {
104
    const dialog = document.getElementById('dialog');
105
    controller = dialog.dialog_controller;
106
    controller.show({ backdrop: "modal-backdrop" });
107
    controller.hide();
108
    const backdrop = document.getElementById("modal-backdrop");
109

  
110
    assert.equal(dialog.style.display, 'none');
111
    assert.isFalse(backdrop.classList.contains('modal-backdrop-open'));
112
  })
113
})
test/javascripts/controllers/dialog_dispatcher_controller.test.js
1
/**
2
 * Redmine - project management software
3
 * Copyright (C) 2006-  Jean-Philippe Lang
4
 * This code is released under the GNU General Public License.
5
 */
6

  
7
import { Application } from "@hotwired/stimulus"
8
import DialogDispatcherController from 'controllers/dialog_dispatcher_controller'
9
import DialogController from 'controllers/dialog_controller'
10
import { assert } from 'chai'
11

  
12
const html = `<div id="dialog" data-controller="dialog" style="display:none">
13
                <button data-action="dialog#hide">close</button>
14
              </div>
15
              <div id="dispatcher" data-controller="dialog-dispatcher" data-dialog-dispatcher-dialog-outlet="#dialog">
16
                <button id="button" data-action="dialog-dispatcher#show" data-dialog-dispatcher-width-param="500px">Show Dialog</button>
17
              </div>
18
              <div id="wrapper"></div>
19
              <div id="modal-backdrop"></div>`;
20

  
21
suite('DialogDispatcherController', () => {
22

  
23
  let container;
24

  
25
  setup(async () => {
26
    container = document.getElementById('container')
27
    const app = Application.start(container);
28
    await app.register('dialog-dispatcher', DialogDispatcherController);
29
    await app.register('dialog', DialogController);
30

  
31
    container.insertAdjacentHTML('afterbegin', html)
32
  });
33

  
34
  teardown(() => {
35
    const clone = container.cloneNode(false);
36
    container.parentNode.replaceChild(clone, container);
37
  });
38

  
39
  test('show the dialog with the specified width', () => {
40
    const button = document.getElementById('button')
41
    button.click();
42

  
43
    const dialog = document.getElementById('dialog')
44
    assert.equal(dialog.style.width, '500px');
45
    assert.equal(dialog.style.display, '');
46
  });
47

  
48
  test('show the dialog when show target is connected', async () => {
49
    const html = `<div id="remote-dialog" data-controller="dialog" data-dialog-dispatcher-target="show" style="display:none" data-width="300px">
50
                <button data-action="dialog#hide">close</button>
51
              </div>`
52

  
53
    const dispatcher = document.getElementById('dispatcher')
54
    dispatcher.insertAdjacentHTML('afterbegin', html)
55

  
56
    const remotedialog = await document.getElementById('remote-dialog')
57
    assert.equal(remotedialog.style.width, '300px');
58
    assert.equal(remotedialog.style.display, '');
59
  });
60

  
61
  test('hide the dialog when hide target is Connected', async () => {
62
    const button = document.getElementById('button')
63
    button.click();
64

  
65
    const dialog = document.getElementById('dialog')
66
    const dispatcher = document.getElementById('dispatcher')
67
    await dispatcher.insertAdjacentHTML('afterbegin', '<template data-dialog-dispatcher-target="hide"></template>')
68
    assert.equal(dialog.style.display, 'none');
69

  
70
    const target = document.querySelector('[data-dialog-dispatcher-target=hide]')
71
    assert.isNull(target)
72
  });
73
});
(2-2/2)