capybara-simulated 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 999617de5641feceb00fff9d815cb9afeac95fc885c2d9893681a0e8a2be3905
4
- data.tar.gz: fb61725ff06cb94851337b4b818d2fdeef2fdf130d00617b02aaed0b13d2799d
3
+ metadata.gz: 3d7b5f908d1c75a41fabf90b90c779ae21813de6a4620a7b574e4dfca69134cf
4
+ data.tar.gz: 57ddffb46aca509cd981106c4ac0ad421d38956c52fba5d439add59ae2e10aab
5
5
  SHA512:
6
- metadata.gz: c7643ae9ebd341be18df9b7cfea6b21ef2fa4c6c83fd9904010d253ffaae4b3680a173961990522c1c39b259e5130d459ecc734145da186d6a4678c47de5458c
7
- data.tar.gz: '09e4ea2fa27a537ddf0c7d11e2292e420dd468de4ec2607723cb9c23b39ca4a480d44a5b6d2871e66f882b445aa59875c5e56855078adcb0d53eb2adb7fb5f72'
6
+ metadata.gz: 576d88b9d8fe7d0c480e8ad7309e7861d9be563a95ab992f6d870f66c06a12d0255f779622ac25e7bab19aa7c6868bf929593e31fe146b4b3fe4d01e3447a37b
7
+ data.tar.gz: 8cfe9a00eff04e4df4d8aa3b1938f122001a00bc7e15f0f3c5b92975fd51c82b2d115aa9b5031ead063a236e4b4c81159ec9d947ea7e5df948e165d5047f3055
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Simulated
3
- VERSION = '0.0.6'
3
+ VERSION = '0.0.7'
4
4
  end
5
5
  end
data/vendor/js/prelude.js CHANGED
@@ -131,6 +131,7 @@
131
131
  globalThis.__csim_runTimers = function (ms) {
132
132
  const advance = (typeof ms === 'number') ? Math.max(0, ms) : Infinity;
133
133
  _virtualClock += advance;
134
+ let everFired = false;
134
135
  while (true) {
135
136
  let fired = false;
136
137
  const due = [];
@@ -141,10 +142,13 @@
141
142
  _timers.delete(id);
142
143
  try { t.fn(); } catch (_) {}
143
144
  fired = true;
145
+ everFired = true;
144
146
  }
145
147
  if (!fired) break;
146
148
  }
149
+ return everFired;
147
150
  };
151
+ globalThis.__csim_pendingTimerCount = function () { return _timers.size; };
148
152
  globalThis.__csim_clearTimers = function () {
149
153
  _timers.clear();
150
154
  _virtualClock = 0;
data/vendor/js/runtime.js CHANGED
@@ -11,6 +11,19 @@
11
11
 
12
12
  const handles = new Map();
13
13
  let nextHandleId = 0;
14
+
15
+ // Capybara's `have_text` matchers and several internal checks call into
16
+ // `visibleText` repeatedly against the same handle while polling. The
17
+ // text-collection walks happy-dom's textContent / styles each call, so
18
+ // re-running it 1000+ times per spec adds up. Cache by handle and drop
19
+ // the whole cache the moment any mutating runtime method runs (or
20
+ // `drainTimers` advances the virtual clock — Stimulus / Turbo timers
21
+ // may have rewritten the page). The cache is intentionally narrow:
22
+ // we measured a broader MutationObserver-driven cache as a wash, since
23
+ // the dispatch overhead ate the cache wins; pinning a bare `Map.clear()`
24
+ // to known-mutating call sites is much cheaper.
25
+ const visibleTextCache = new Map();
26
+ function clearReadCache() { if (visibleTextCache.size) visibleTextCache.clear(); }
14
27
  let currentWindow = null;
15
28
  let currentDocument = null;
16
29
  let activeHandleId = null;
@@ -47,6 +60,7 @@
47
60
  catch (_) {}
48
61
  }
49
62
  handles.clear();
63
+ visibleTextCache.clear();
50
64
  nextHandleId = 0;
51
65
  activeHandleId = null;
52
66
  modalQueue.length = 0;
@@ -890,8 +904,9 @@
890
904
 
891
905
  function drainTimers(ms) {
892
906
  if (typeof globalThis.__csim_runTimers === 'function') {
893
- try { globalThis.__csim_runTimers(ms); } catch (_) {}
907
+ try { return !!globalThis.__csim_runTimers(ms); } catch (_) {}
894
908
  }
909
+ return false;
895
910
  }
896
911
 
897
912
  // happy-dom has no layout engine, so getBoundingClientRect always returns
@@ -1308,10 +1323,13 @@
1308
1323
  },
1309
1324
  allText(id) { return String(lookup(id).textContent || ''); },
1310
1325
  visibleText(id) {
1326
+ const cached = visibleTextCache.get(id);
1327
+ if (cached !== undefined) return cached;
1311
1328
  const el = lookup(id);
1312
1329
  // If any ancestor of `el` is hidden, the element renders nothing.
1313
- if (!visibleAncestorChainOk(el)) return '';
1314
- return String(visibleTextOf(el));
1330
+ const txt = visibleAncestorChainOk(el) ? String(visibleTextOf(el)) : '';
1331
+ visibleTextCache.set(id, txt);
1332
+ return txt;
1315
1333
  },
1316
1334
  path(id) { return String(buildXPath(lookup(id))); },
1317
1335
  rect(id) {
@@ -1350,6 +1368,7 @@
1350
1368
  },
1351
1369
 
1352
1370
  setValue(id, value) {
1371
+ clearReadCache();
1353
1372
  const el = lookup(id);
1354
1373
  const tag = (el.tagName || '').toUpperCase();
1355
1374
  const type = (el.type || (el.getAttribute && el.getAttribute('type')) || '').toLowerCase();
@@ -1457,6 +1476,7 @@
1457
1476
  },
1458
1477
 
1459
1478
  selectOption(id) {
1479
+ clearReadCache();
1460
1480
  const opt = lookup(id);
1461
1481
  const select = opt.parentNode && (opt.parentNode.tagName === 'SELECT'
1462
1482
  ? opt.parentNode
@@ -1475,6 +1495,7 @@
1475
1495
  return true;
1476
1496
  },
1477
1497
  unselectOption(id) {
1498
+ clearReadCache();
1478
1499
  const opt = lookup(id);
1479
1500
  const select = opt.closest && opt.closest('select');
1480
1501
  if (!select || !isMultipleSelect(select)) return false;
@@ -1521,8 +1542,8 @@
1521
1542
  boolPropOrAttr(lookup(id), 'readonly'); },
1522
1543
  multiple(id) { return boolPropOrAttr(lookup(id), 'multiple'); },
1523
1544
 
1524
- focus(id) { activeHandleId = id; lookup(id).dispatchEvent(makeEvent('focus', {bubbles: false})); return true; },
1525
- blur(id) { lookup(id).dispatchEvent(makeEvent('blur', {bubbles: false})); if (activeHandleId === id) activeHandleId = null; return true; },
1545
+ focus(id) { clearReadCache(); activeHandleId = id; lookup(id).dispatchEvent(makeEvent('focus', {bubbles: false})); return true; },
1546
+ blur(id) { clearReadCache(); lookup(id).dispatchEvent(makeEvent('blur', {bubbles: false})); if (activeHandleId === id) activeHandleId = null; return true; },
1526
1547
  activeElement() {
1527
1548
  // Honour the JS-side `document.activeElement` first — happy-dom
1528
1549
  // updates it when scripts call `focus()` directly, which the
@@ -1534,14 +1555,22 @@
1534
1555
  },
1535
1556
 
1536
1557
  hover(id) {
1558
+ clearReadCache();
1537
1559
  const el = lookup(id);
1538
1560
  el.dispatchEvent(makeEvent('mouseover'));
1539
1561
  el.dispatchEvent(makeEvent('mouseenter', {bubbles: false}));
1540
1562
  return true;
1541
1563
  },
1542
- trigger(id, name) { lookup(id).dispatchEvent(makeEvent(name)); return true; },
1543
-
1544
- drainTimers(ms) { drainTimers(ms); return true; },
1564
+ trigger(id, name) { clearReadCache(); lookup(id).dispatchEvent(makeEvent(name)); return true; },
1565
+
1566
+ drainTimers(ms) {
1567
+ // Only clear the read cache if a timer actually fired — most
1568
+ // `advance_virtual_clock` calls from Ruby have nothing to do but
1569
+ // tick the wall clock. Without this the visibleText cache is
1570
+ // invalidated on every cross-bridge call and never hits.
1571
+ if (drainTimers(ms)) clearReadCache();
1572
+ return true;
1573
+ },
1545
1574
 
1546
1575
  consumeHistoryPushed() {
1547
1576
  const v = _historyPushed;
@@ -1564,6 +1593,7 @@
1564
1593
  },
1565
1594
 
1566
1595
  click(id, button, modifiers, skipDown) {
1596
+ clearReadCache();
1567
1597
  const el = lookup(id);
1568
1598
  activeHandleId = id;
1569
1599
  const m = Object.assign({button: button || 0}, modifiers || {});
@@ -1710,6 +1740,7 @@
1710
1740
  },
1711
1741
 
1712
1742
  doubleClick(id, modifiers) {
1743
+ clearReadCache();
1713
1744
  const el = lookup(id);
1714
1745
  const m = Object.assign({button: 0}, modifiers || {});
1715
1746
  applyClickOffset(el, m);
@@ -1723,6 +1754,7 @@
1723
1754
  return {action: 'none'};
1724
1755
  },
1725
1756
  rightClick(id, modifiers, skipDown) {
1757
+ clearReadCache();
1726
1758
  const el = lookup(id);
1727
1759
  const m = Object.assign({button: 2}, modifiers || {});
1728
1760
  applyClickOffset(el, m);
@@ -1738,6 +1770,7 @@
1738
1770
  // exposes `DragEvent` as a plain `Event`, so we paste `dataTransfer`
1739
1771
  // onto each event before dispatch.
1740
1772
  drop(id, items) {
1773
+ clearReadCache();
1741
1774
  const el = lookup(id);
1742
1775
  const win = currentWindow;
1743
1776
  const dt = new win.DataTransfer();
@@ -1764,9 +1797,10 @@
1764
1797
  return true;
1765
1798
  },
1766
1799
 
1767
- submit(id) { return submitDescriptor(lookup(id), null); },
1800
+ submit(id) { clearReadCache(); return submitDescriptor(lookup(id), null); },
1768
1801
 
1769
1802
  sendKeys(id, keys) {
1803
+ clearReadCache();
1770
1804
  const el = lookup(id);
1771
1805
  const editable = (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA');
1772
1806
  let formToSubmit = null;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-simulated
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keita Urashima