@rvoh/psychic-spec-helpers 0.3.1-fgbeta-9 → 0.4.0

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.
Files changed (56) hide show
  1. package/dist/esm/src/feature/helpers/{launchViteServer.js → launchDevServer.js} +25 -20
  2. package/dist/esm/src/feature/helpers/metaOrControlKey.js +4 -0
  3. package/dist/esm/src/feature/helpers/providePuppeteerViteMatchers.js +26 -26
  4. package/dist/esm/src/feature/helpers/visit.js +0 -1
  5. package/dist/esm/src/feature/matchers/toCheck.js +15 -20
  6. package/dist/esm/src/feature/matchers/toClick.js +3 -3
  7. package/dist/esm/src/feature/matchers/toClickButton.js +14 -21
  8. package/dist/esm/src/feature/matchers/toClickLink.js +14 -21
  9. package/dist/esm/src/feature/matchers/toClickSelector.js +14 -21
  10. package/dist/esm/src/feature/matchers/toFill.js +25 -16
  11. package/dist/esm/src/feature/matchers/toHaveChecked.js +13 -14
  12. package/dist/esm/src/feature/matchers/toHaveLink.js +14 -22
  13. package/dist/esm/src/feature/matchers/toHavePath.js +3 -1
  14. package/dist/esm/src/feature/matchers/toHaveSelector.js +2 -2
  15. package/dist/esm/src/feature/matchers/toHaveUnchecked.js +13 -14
  16. package/dist/esm/src/feature/matchers/toNotHaveSelector.js +14 -13
  17. package/dist/esm/src/feature/matchers/toUncheck.js +22 -19
  18. package/dist/esm/src/index.js +1 -1
  19. package/dist/types/src/feature/helpers/launchDevServer.d.ts +7 -0
  20. package/dist/types/src/feature/helpers/metaOrControlKey.d.ts +1 -0
  21. package/dist/types/src/feature/helpers/visit.d.ts +1 -1
  22. package/dist/types/src/feature/matchers/toCheck.d.ts +6 -3
  23. package/dist/types/src/feature/matchers/toClick.d.ts +2 -2
  24. package/dist/types/src/feature/matchers/toClickButton.d.ts +6 -3
  25. package/dist/types/src/feature/matchers/toClickLink.d.ts +6 -3
  26. package/dist/types/src/feature/matchers/toClickSelector.d.ts +6 -3
  27. package/dist/types/src/feature/matchers/toFill.d.ts +6 -3
  28. package/dist/types/src/feature/matchers/toHaveChecked.d.ts +6 -3
  29. package/dist/types/src/feature/matchers/toHaveLink.d.ts +3 -3
  30. package/dist/types/src/feature/matchers/toHaveSelector.d.ts +2 -2
  31. package/dist/types/src/feature/matchers/toHaveUnchecked.d.ts +3 -3
  32. package/dist/types/src/feature/matchers/toMatchTextContent.d.ts +2 -2
  33. package/dist/types/src/feature/matchers/toNotHaveSelector.d.ts +3 -3
  34. package/dist/types/src/feature/matchers/toUncheck.d.ts +8 -2
  35. package/dist/types/src/index.d.ts +15 -14
  36. package/package.json +1 -2
  37. package/src/feature/helpers/{launchViteServer.ts → launchDevServer.ts} +35 -25
  38. package/src/feature/helpers/metaOrControlKey.ts +4 -0
  39. package/src/feature/helpers/providePuppeteerViteMatchers.ts +32 -28
  40. package/src/feature/helpers/visit.ts +0 -1
  41. package/src/feature/matchers/toCheck.ts +20 -30
  42. package/src/feature/matchers/toClick.ts +8 -7
  43. package/src/feature/matchers/toClickButton.ts +20 -25
  44. package/src/feature/matchers/toClickLink.ts +20 -25
  45. package/src/feature/matchers/toClickSelector.ts +20 -25
  46. package/src/feature/matchers/toFill.ts +36 -23
  47. package/src/feature/matchers/toHaveChecked.ts +23 -22
  48. package/src/feature/matchers/toHaveLink.ts +19 -27
  49. package/src/feature/matchers/toHavePath.ts +3 -1
  50. package/src/feature/matchers/toHaveSelector.ts +7 -3
  51. package/src/feature/matchers/toHaveUnchecked.ts +23 -22
  52. package/src/feature/matchers/toMatchTextContent.ts +2 -2
  53. package/src/feature/matchers/toNotHaveSelector.ts +17 -18
  54. package/src/feature/matchers/toUncheck.ts +28 -29
  55. package/src/index.ts +19 -14
  56. package/dist/types/src/feature/helpers/launchViteServer.d.ts +0 -6
@@ -1,14 +1,14 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { createServer } from 'net';
3
3
  import sleep from '../../shared/sleep.js';
4
- let serverProcess = undefined;
5
- export default async function launchViteServer({ port = 3000, cmd = 'yarn client', timeout = 5000, } = {}) {
6
- if (serverProcess)
4
+ const devServerProcesses = {};
5
+ export default async function launchDevServer(key, { port = 3000, cmd = 'yarn client', timeout = 5000, } = {}) {
6
+ if (devServerProcesses[key])
7
7
  return;
8
8
  if (process.env.DEBUG === '1')
9
9
  console.log('Starting server...');
10
10
  const [_cmd, ...args] = cmd.split(' ');
11
- serverProcess = spawn(_cmd, args, {
11
+ const proc = spawn(_cmd, args, {
12
12
  detached: true,
13
13
  env: {
14
14
  ...process.env,
@@ -16,41 +16,46 @@ export default async function launchViteServer({ port = 3000, cmd = 'yarn client
16
16
  VITE_PSYCHIC_ENV: 'test',
17
17
  },
18
18
  });
19
- await waitForPort(port, timeout);
20
- serverProcess.stdout.on('data', data => {
21
- if (process.env.DEBUG === '1')
22
- console.log(`Server output: ${data}`);
23
- });
24
- serverProcess.on('error', err => {
19
+ await waitForPort(key, port, timeout);
20
+ proc.on('error', err => {
25
21
  throw err;
26
22
  });
27
- serverProcess.stdout.on('data', data => {
23
+ proc.stdout.on('data', data => {
28
24
  if (process.env.DEBUG === '1')
29
25
  console.log(`Server output: ${data}`);
30
26
  });
31
- serverProcess.stderr.on('data', data => {
27
+ proc.stderr.on('data', data => {
32
28
  if (process.env.DEBUG === '1')
33
29
  console.error(`Server error: ${data}`);
34
30
  });
35
- serverProcess.on('error', err => {
31
+ proc.on('error', err => {
36
32
  console.error(`Server process error: ${err}`);
37
33
  });
38
- serverProcess.on('close', code => {
34
+ proc.on('close', code => {
39
35
  if (process.env.DEBUG === '1')
40
36
  console.log(`Server process exited with code ${code}`);
41
37
  });
42
38
  }
43
- export function stopViteServer() {
44
- if (serverProcess?.pid) {
39
+ export function stopDevServer(key) {
40
+ const proc = devServerProcesses[key];
41
+ if (!proc) {
42
+ throw new Error(`Cannot find a dev server by the key: ${key}`);
43
+ }
44
+ if (proc?.pid) {
45
45
  if (process.env.DEBUG === '1')
46
46
  console.log('Stopping server...');
47
47
  // serverProcess.kill('SIGINT')
48
- process.kill(-serverProcess.pid, 'SIGKILL');
49
- serverProcess = undefined;
48
+ process.kill(-proc.pid, 'SIGKILL');
49
+ delete devServerProcesses[key];
50
50
  if (process.env.DEBUG === '1')
51
51
  console.log('server stopped');
52
52
  }
53
53
  }
54
+ export function stopDevServers() {
55
+ Object.keys(devServerProcesses).forEach(key => {
56
+ stopDevServer(key);
57
+ });
58
+ }
54
59
  async function isPortAvailable(port) {
55
60
  return new Promise(resolve => {
56
61
  const server = createServer()
@@ -69,7 +74,7 @@ async function isPortAvailable(port) {
69
74
  .listen(port, '127.0.0.1');
70
75
  });
71
76
  }
72
- async function waitForPort(port, timeout = 5000) {
77
+ async function waitForPort(key, port, timeout = 5000) {
73
78
  if (await isPortAvailable(port)) {
74
79
  return true;
75
80
  }
@@ -79,7 +84,7 @@ async function waitForPort(port, timeout = 5000) {
79
84
  return true;
80
85
  }
81
86
  if (Date.now() > startTime + timeout) {
82
- stopViteServer();
87
+ stopDevServer(key);
83
88
  throw new Error('waited too long for port: ' + port);
84
89
  }
85
90
  await sleep(50);
@@ -0,0 +1,4 @@
1
+ export default function metaOrControlKey() {
2
+ // Use 'Meta' for macOS and 'Control' for Windows/Linux
3
+ return process.platform === 'darwin' ? 'Meta' : 'Control';
4
+ }
@@ -18,32 +18,32 @@ import toFill from '../matchers/toFill.js';
18
18
  export default function providePuppeteerViteMatchers() {
19
19
  ;
20
20
  global.expect.extend({
21
- async toMatchTextContent(page, text) {
22
- return await toMatchTextContent(page, text);
21
+ async toMatchTextContent(page, text, opts) {
22
+ return await toMatchTextContent(page, text, opts);
23
23
  },
24
24
  async toNotMatchTextContent(page, text) {
25
25
  return await toNotMatchTextContent(page, text);
26
26
  },
27
- async toHaveSelector(page, cssSelector) {
28
- return await toHaveSelector(page, cssSelector);
27
+ async toHaveSelector(page, cssSelector, opts) {
28
+ return await toHaveSelector(page, cssSelector, opts);
29
29
  },
30
- async toNotHaveSelector(page, cssSelector) {
31
- return await toNotHaveSelector(page, cssSelector);
30
+ async toNotHaveSelector(page, cssSelector, opts) {
31
+ return await toNotHaveSelector(page, cssSelector, opts);
32
32
  },
33
- async toCheck(page, text) {
34
- return await toCheck(page, text);
33
+ async toCheck(page, text, opts) {
34
+ return await toCheck(page, text, opts);
35
35
  },
36
- async toClick(page, text) {
37
- return await toClick(page, text);
36
+ async toClick(page, text, opts) {
37
+ return await toClick(page, text, opts);
38
38
  },
39
- async toClickLink(page, text) {
40
- return await toClickLink(page, text);
39
+ async toClickLink(page, text, opts) {
40
+ return await toClickLink(page, text, opts);
41
41
  },
42
- async toClickButton(page, text) {
43
- return await toClickButton(page, text);
42
+ async toClickButton(page, text, opts) {
43
+ return await toClickButton(page, text, opts);
44
44
  },
45
- async toClickSelector(page, cssSelector) {
46
- return await toClickSelector(page, cssSelector);
45
+ async toClickSelector(page, cssSelector, opts) {
46
+ return await toClickSelector(page, cssSelector, opts);
47
47
  },
48
48
  async toHavePath(page, path) {
49
49
  return await toHavePath(page, path);
@@ -51,20 +51,20 @@ export default function providePuppeteerViteMatchers() {
51
51
  async toHaveUrl(page, url) {
52
52
  return await toHaveUrl(page, url);
53
53
  },
54
- async toHaveChecked(page, text) {
55
- return await toHaveChecked(page, text);
54
+ async toHaveChecked(page, text, opts) {
55
+ return await toHaveChecked(page, text, opts);
56
56
  },
57
- async toHaveUnchecked(page, checked) {
58
- return await toHaveUnchecked(page, checked);
57
+ async toHaveUnchecked(page, checked, opts) {
58
+ return await toHaveUnchecked(page, checked, opts);
59
59
  },
60
- async toHaveLink(page, text) {
61
- return await toHaveLink(page, text);
60
+ async toHaveLink(page, text, opts) {
61
+ return await toHaveLink(page, text, opts);
62
62
  },
63
- async toFill(page, cssSelector, text) {
64
- return await toFill(page, cssSelector, text);
63
+ async toFill(page, cssSelector, text, opts) {
64
+ return await toFill(page, cssSelector, text, opts);
65
65
  },
66
- async toUncheck(page, text) {
67
- return await toUncheck(page, text);
66
+ async toUncheck(page, text, opts) {
67
+ return await toUncheck(page, text, opts);
68
68
  },
69
69
  async toEvaluate(argumentPassedToExpect, evaluationFn, opts) {
70
70
  return await evaluateWithRetryAndTimeout(argumentPassedToExpect, evaluationFn, opts);
@@ -1,4 +1,3 @@
1
1
  export default async function visit(path, { baseUrl = 'http://localhost:3000' } = {}) {
2
2
  await page.goto(`${baseUrl}/${path.replace(/^\//, '')}`);
3
- return page;
4
3
  }
@@ -1,23 +1,18 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import evaluationFailure from '../internal/evaluationFailure.js';
3
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
4
- export default async function toCheck(page, expectedText) {
5
- return await evaluateWithRetryAndTimeout(page, async () => {
6
- requirePuppeteerPage(page);
7
- const checkbox = await page.$(`input[type="checkbox"][value="${expectedText}"]`);
8
- if (!checkbox)
9
- return evaluationFailure(`A checkbox was not found with "${expectedText}"`);
10
- const isChecked = await page.evaluate(checkbox => checkbox.checked, checkbox);
11
- if (isChecked)
12
- return evaluationFailure(`A checkbox was found with "${expectedText}", but it is already checked`);
13
- await checkbox.click();
14
- const isCheckedNow = await page.evaluate(checkbox => checkbox.checked, checkbox);
1
+ export default async function toCheck(page, expectedText, opts) {
2
+ try {
3
+ const el = await page.waitForSelector(`label::-p-text(${expectedText}`, opts);
4
+ await el.click();
15
5
  return {
16
- pass: isCheckedNow,
17
- actual: expectedText,
6
+ pass: true,
7
+ message: () => {
8
+ throw new Error('Cannot negate toCheck');
9
+ },
18
10
  };
19
- }, {
20
- successText: r => `Expected page to have checkable checkbox with text: "${expectedText}"`,
21
- failureText: r => `Expected page not to have checkable checkbox with text: "${expectedText}"`,
22
- });
11
+ }
12
+ catch (error) {
13
+ return {
14
+ pass: false,
15
+ message: `Expected page to have checkable element with text: "${expectedText}"`,
16
+ };
17
+ }
23
18
  }
@@ -1,11 +1,11 @@
1
- export default async function toClick(page, expectedText) {
1
+ export default async function toClick(page, expectedText, opts) {
2
2
  try {
3
- const el = await page.waitForSelector(`*::-p-text(${expectedText})`);
3
+ const el = await page.waitForSelector(`*::-p-text(${expectedText})`, opts);
4
4
  await el.click();
5
5
  return {
6
6
  pass: true,
7
7
  message: () => {
8
- throw new Error('Cannot negate toNotMatchTextContent, use toMatchTextContent instead');
8
+ throw new Error('Cannot negate toClick');
9
9
  },
10
10
  };
11
11
  }
@@ -1,25 +1,18 @@
1
- import { TimeoutError } from 'puppeteer';
2
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
3
- import evaluationFailure from '../internal/evaluationFailure.js';
4
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
5
- export default async function toClickButton(page, expectedText) {
6
- return await evaluateWithRetryAndTimeout(page, async () => {
7
- requirePuppeteerPage(page);
8
- try {
9
- ;
10
- (await page.$('button::-p-text(Submit)')).click();
11
- }
12
- catch (err) {
13
- if (err instanceof TimeoutError)
14
- return evaluationFailure(expectedText);
15
- throw err;
16
- }
1
+ export default async function toClickButton(page, expectedText, opts) {
2
+ try {
3
+ const el = await page.waitForSelector('button::-p-text(Submit)', opts);
4
+ await el.click();
17
5
  return {
18
6
  pass: true,
19
- actual: expectedText,
7
+ message: () => {
8
+ throw new Error('Cannot negate toClickLink');
9
+ },
20
10
  };
21
- }, {
22
- successText: () => `Expected page to have clickable button with text: "${expectedText}"`,
23
- failureText: () => `Expected page not to have clickable button with text: "${expectedText}"`,
24
- });
11
+ }
12
+ catch (error) {
13
+ return {
14
+ pass: false,
15
+ message: `Expected page to have clickable link with matching text: "${expectedText}"`,
16
+ };
17
+ }
25
18
  }
@@ -1,25 +1,18 @@
1
- import { TimeoutError } from 'puppeteer';
2
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
3
- import evaluationFailure from '../internal/evaluationFailure.js';
4
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
5
- export default async function toClickLink(page, expectedText) {
6
- return await evaluateWithRetryAndTimeout(page, async () => {
7
- requirePuppeteerPage(page);
8
- try {
9
- ;
10
- (await page.$(`a ::-p-text(${expectedText})`)).click();
11
- }
12
- catch (err) {
13
- if (err instanceof TimeoutError)
14
- return evaluationFailure(expectedText);
15
- throw err;
16
- }
1
+ export default async function toClickLink(page, expectedText, opts) {
2
+ try {
3
+ const el = await page.waitForSelector(`a ::-p-text(${expectedText})`, opts);
4
+ await el.click();
17
5
  return {
18
6
  pass: true,
19
- actual: expectedText,
7
+ message: () => {
8
+ throw new Error('Cannot negate toClickLink');
9
+ },
20
10
  };
21
- }, {
22
- successText: () => `Expected page to have clickable link with text: "${expectedText}"`,
23
- failureText: () => `Expected page not to have clickable link with text: "${expectedText}"`,
24
- });
11
+ }
12
+ catch (error) {
13
+ return {
14
+ pass: false,
15
+ message: `Expected page to have clickable link with matching text: "${expectedText}"`,
16
+ };
17
+ }
25
18
  }
@@ -1,25 +1,18 @@
1
- import { TimeoutError } from 'puppeteer';
2
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
3
- import evaluationFailure from '../internal/evaluationFailure.js';
4
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
5
- export default async function toClickSelector(page, cssSelector) {
6
- return await evaluateWithRetryAndTimeout(page, async () => {
7
- requirePuppeteerPage(page);
8
- try {
9
- ;
10
- (await page.$(cssSelector)).click();
11
- }
12
- catch (err) {
13
- if (err instanceof TimeoutError)
14
- return evaluationFailure(cssSelector);
15
- throw err;
16
- }
1
+ export default async function toClickSelector(page, cssSelector, opts) {
2
+ try {
3
+ const el = await page.waitForSelector(cssSelector, opts);
4
+ await el.click();
17
5
  return {
18
6
  pass: true,
19
- actual: cssSelector,
7
+ message: () => {
8
+ throw new Error('Cannot negate toNotMatchTextContent, use toMatchTextContent instead');
9
+ },
20
10
  };
21
- }, {
22
- successText: () => `Expected page to have clickable selector with text: "${cssSelector}"`,
23
- failureText: () => `Expected page not to have clickable selector with text: "${cssSelector}"`,
24
- });
11
+ }
12
+ catch (error) {
13
+ return {
14
+ pass: false,
15
+ message: `Expected page to have clickable element with matching selector: "${cssSelector}"`,
16
+ };
17
+ }
25
18
  }
@@ -1,21 +1,30 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import evaluationFailure from '../internal/evaluationFailure.js';
3
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
4
- export default async function toFill(page, cssSelector, text) {
5
- return await evaluateWithRetryAndTimeout(page, async () => {
6
- requirePuppeteerPage(page);
7
- try {
8
- await page.type(cssSelector, text);
9
- }
10
- catch {
11
- return evaluationFailure(text);
1
+ import metaOrControlKey from '../helpers/metaOrControlKey.js';
2
+ export default async function toFill(page, cssSelector, text, opts) {
3
+ try {
4
+ await page.waitForSelector(cssSelector, opts);
5
+ // unless the user opts out, clear the input
6
+ // before typing into it, since most of the
7
+ // time this is what people will expect to
8
+ // happen.
9
+ if (!opts?.bypassInputValueReset) {
10
+ await page.focus(cssSelector);
11
+ await page.keyboard.down(metaOrControlKey());
12
+ await page.keyboard.press('A');
13
+ await page.keyboard.up(metaOrControlKey());
14
+ await page.keyboard.press('Backspace');
12
15
  }
16
+ await page.type(cssSelector, text);
13
17
  return {
14
18
  pass: true,
15
- actual: text,
19
+ message: () => {
20
+ throw new Error('cannot negate toFill');
21
+ },
22
+ };
23
+ }
24
+ catch {
25
+ return {
26
+ pass: false,
27
+ message: () => `failed to fill input matching selector ${cssSelector} with text "text"`,
16
28
  };
17
- }, {
18
- successText: () => `Expected page to have clickable link with text: "${text}"`,
19
- failureText: () => `Expected page not to have clickable link with text: "${text}"`,
20
- });
29
+ }
21
30
  }
@@ -1,19 +1,18 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import evaluationFailure from '../internal/evaluationFailure.js';
3
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
4
- export default async function toHaveChecked(page, expectedText) {
5
- return await evaluateWithRetryAndTimeout(page, async () => {
6
- requirePuppeteerPage(page);
7
- const checkbox = await page.$(`input[type="checkbox"][value="${expectedText}"]`);
8
- if (!checkbox)
9
- return evaluationFailure(`A checkbox was not found with "${expectedText}"`);
1
+ export default async function toHaveChecked(page, expectedText, opts) {
2
+ try {
3
+ const checkbox = await page.waitForSelector(`input[type="checkbox"][value="${expectedText}"]`, opts);
10
4
  const isChecked = await page.evaluate(checkbox => checkbox.checked, checkbox);
11
5
  return {
12
6
  pass: isChecked,
13
- actual: expectedText,
7
+ message: () => {
8
+ throw new Error('cannot negate toHaveChecked, try toHaveUnchecked');
9
+ },
14
10
  };
15
- }, {
16
- successText: r => `Expected page to have checked checkbox with text: "${expectedText}"`,
17
- failureText: r => `Expected page not to have checked checkbox with text: "${expectedText}"`,
18
- });
11
+ }
12
+ catch {
13
+ return {
14
+ pass: false,
15
+ message: () => `Expected page to have checked checkbox with text: "${expectedText}"`,
16
+ };
17
+ }
19
18
  }
@@ -1,25 +1,17 @@
1
- import { TimeoutError } from 'puppeteer';
2
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
3
- import evaluationFailure from '../internal/evaluationFailure.js';
4
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
5
- export default async function toHaveLink(page, expectedText) {
6
- return await evaluateWithRetryAndTimeout(page, async () => {
7
- requirePuppeteerPage(page);
8
- let el = undefined;
9
- try {
10
- el = await page.locator(`a ::-p-text(${expectedText})`).setTimeout(10).wait();
11
- }
12
- catch (err) {
13
- if (err instanceof TimeoutError)
14
- return evaluationFailure(expectedText);
15
- throw err;
16
- }
1
+ export default async function toHaveLink(page, expectedText, opts) {
2
+ try {
3
+ await page.waitForSelector(`a ::-p-text(${expectedText})`, opts);
17
4
  return {
18
- pass: !!el,
19
- actual: expectedText,
5
+ pass: true,
6
+ message: () => {
7
+ throw new Error('cannot negate toFill');
8
+ },
20
9
  };
21
- }, {
22
- successText: () => `Expected page to have clickable link with text: "${expectedText}"`,
23
- failureText: () => `Expected page not to have clickable link with text: "${expectedText}"`,
24
- });
10
+ }
11
+ catch {
12
+ return {
13
+ pass: false,
14
+ message: () => `Expected page not to have checked checkbox with text: "${expectedText}"`,
15
+ };
16
+ }
25
17
  }
@@ -9,7 +9,9 @@ export default async function toHavePath(page, expectedPath) {
9
9
  actual: expectedPath,
10
10
  };
11
11
  }, {
12
- successText: () => `Expected page to have path: "${expectedPath}"`,
12
+ successText: () => {
13
+ throw new Error('cannot negate toHavePath');
14
+ },
13
15
  failureText: () => `Expected page not to have path: "${expectedPath}"`,
14
16
  });
15
17
  }
@@ -1,6 +1,6 @@
1
- export default async function toHaveSelector(page, selector) {
1
+ export default async function toHaveSelector(page, selector, opts) {
2
2
  try {
3
- await page.waitForSelector(selector);
3
+ await page.waitForSelector(selector, opts);
4
4
  return {
5
5
  pass: true,
6
6
  message: () => {
@@ -1,19 +1,18 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import evaluationFailure from '../internal/evaluationFailure.js';
3
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
4
- export default async function toHaveUnchecked(page, expectedText) {
5
- return await evaluateWithRetryAndTimeout(page, async () => {
6
- requirePuppeteerPage(page);
7
- const checkbox = await page.$(`input[type="checkbox"][value="${expectedText}"]`);
8
- if (!checkbox)
9
- return evaluationFailure(`A checkbox was not found with "${expectedText}"`);
1
+ export default async function toHaveUnchecked(page, expectedText, opts) {
2
+ try {
3
+ const checkbox = await page.waitForSelector(`input[type="checkbox"][value="${expectedText}"]`, opts);
10
4
  const isChecked = await page.evaluate(checkbox => checkbox.checked, checkbox);
11
5
  return {
12
6
  pass: !isChecked,
13
- actual: expectedText,
7
+ message: () => {
8
+ throw new Error('cannot negate toHaveUnchecked, try toHaveChecked');
9
+ },
14
10
  };
15
- }, {
16
- successText: r => `Expected page to have unchecked checkbox with text: "${expectedText}"`,
17
- failureText: r => `Expected page not to have unchecked checkbox with text: "${expectedText}"`,
18
- });
11
+ }
12
+ catch {
13
+ return {
14
+ pass: false,
15
+ message: () => `Expected page not to have checked checkbox with text: "${expectedText}"`,
16
+ };
17
+ }
19
18
  }
@@ -1,16 +1,17 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
3
- export default async function toNotHaveSelector(page, selector) {
4
- return await evaluateWithRetryAndTimeout(page, async () => {
5
- requirePuppeteerPage(page);
1
+ export default async function toNotHaveSelector(page, selector, opts) {
2
+ try {
3
+ await page.waitForSelector(selector, { hidden: true, ...opts });
6
4
  return {
7
- pass: !(await page.$(selector)),
8
- actual: selector,
5
+ pass: true,
6
+ message: () => {
7
+ throw new Error('Cannot negate toNotHaveSelector, use toHaveSelector instead');
8
+ },
9
9
  };
10
- }, {
11
- successText: () => {
12
- throw new Error('Cannot negate toNotHaveSelector, use toHaveSelector instead');
13
- },
14
- failureText: r => `Expected ${r} to have selector: ${selector}`,
15
- });
10
+ }
11
+ catch {
12
+ return {
13
+ pass: false,
14
+ message: () => `Expected page to not have visible selector, but it did: ${selector}`,
15
+ };
16
+ }
16
17
  }
@@ -1,23 +1,26 @@
1
- import evaluateWithRetryAndTimeout from '../internal/evaluateWithRetryAndTimeout.js';
2
- import evaluationFailure from '../internal/evaluationFailure.js';
3
- import requirePuppeteerPage from '../internal/requirePuppeteerPage.js';
4
- export default async function toUncheck(page, expectedText) {
5
- return await evaluateWithRetryAndTimeout(page, async () => {
6
- requirePuppeteerPage(page);
7
- const checkbox = await page.$(`input[type="checkbox"][value="${expectedText}"]`);
8
- if (!checkbox)
9
- return evaluationFailure(`A checkbox was not found with "${expectedText}"`);
10
- const isChecked = await page.evaluate(checkbox => checkbox.checked, checkbox);
1
+ export default async function toUncheck(page, expectedText, opts) {
2
+ try {
3
+ const el = await page.waitForSelector(`label::-p-text(${expectedText}`, opts);
4
+ await el.click();
5
+ const isChecked = await page.evaluate(checkbox => checkbox.checked, el);
11
6
  if (!isChecked)
12
- return evaluationFailure(`A checkbox was found with "${expectedText}", but it is already unchecked`);
13
- await checkbox.click();
14
- const isCheckedNow = await page.evaluate(checkbox => checkbox.checked, checkbox);
7
+ return {
8
+ pass: false,
9
+ message: () => `A checkbox was found with "${expectedText}", but it is already unchecked`,
10
+ };
11
+ await el.click();
12
+ const isUncheckedNow = await page.evaluate(checkbox => checkbox.checked, el);
15
13
  return {
16
- pass: !isCheckedNow,
17
- actual: expectedText,
14
+ pass: isUncheckedNow,
15
+ message: () => {
16
+ throw new Error('Cannot negate toUncheck, try toCheck');
17
+ },
18
18
  };
19
- }, {
20
- successText: r => `Expected page to have uncheckable checkbox with text: "${expectedText}"`,
21
- failureText: r => `Expected page not to have uncheckable checkbox with text: "${expectedText}"`,
22
- });
19
+ }
20
+ catch (error) {
21
+ return {
22
+ pass: false,
23
+ message: `Expected page to have checkable element with text: "${expectedText}"`,
24
+ };
25
+ }
23
26
  }
@@ -7,6 +7,6 @@ export { SpecSession } from './unit/SpecSession.js';
7
7
  export { default as providePuppeteerViteMatchers } from './feature/helpers/providePuppeteerViteMatchers.js';
8
8
  export { default as launchBrowser } from './feature/helpers/launchBrowser.js';
9
9
  export { default as launchPage } from './feature/helpers/launchPage.js';
10
- export { default as launchViteServer, stopViteServer } from './feature/helpers/launchViteServer.js';
10
+ export { default as launchDevServer, stopDevServers, stopDevServer, } from './feature/helpers/launchDevServer.js';
11
11
  export { default as visit } from './feature/helpers/visit.js';
12
12
  export default {};
@@ -0,0 +1,7 @@
1
+ export default function launchDevServer(key: string, { port, cmd, timeout, }?: {
2
+ port?: number;
3
+ cmd?: string;
4
+ timeout?: number;
5
+ }): Promise<void>;
6
+ export declare function stopDevServer(key: string): void;
7
+ export declare function stopDevServers(): void;