@rvoh/psychic-spec-helpers 0.4.4 → 0.5.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 (196) hide show
  1. package/client/tsconfig.json +7 -0
  2. package/dist/esm/spec/features/check.spec.js +15 -0
  3. package/dist/esm/spec/features/click.spec.js +12 -0
  4. package/dist/esm/spec/features/clickButton.spec.js +12 -0
  5. package/dist/esm/spec/features/clickLink.spec.js +12 -0
  6. package/dist/esm/spec/features/clickSelector.spec.js +12 -0
  7. package/dist/esm/spec/features/fillIn.spec.js +15 -0
  8. package/dist/esm/spec/features/helpers/getPage.js +10 -0
  9. package/dist/esm/spec/features/matchers/toCheck.spec.js +15 -0
  10. package/dist/esm/spec/features/matchers/toClick.spec.js +13 -0
  11. package/dist/esm/spec/features/matchers/toClickButton.spec.js +12 -0
  12. package/dist/esm/spec/features/matchers/toClickLink.spec.js +12 -0
  13. package/dist/esm/spec/features/matchers/toClickSelector.spec.js +12 -0
  14. package/dist/esm/spec/features/matchers/toFill.spec.js +15 -0
  15. package/dist/esm/spec/features/matchers/toHaveChecked.spec.js +13 -0
  16. package/dist/esm/spec/features/matchers/toHaveLink.spec.js +12 -0
  17. package/dist/esm/spec/features/matchers/toHavePath.spec.js +12 -0
  18. package/dist/esm/spec/features/matchers/toHaveSelector.spec.js +12 -0
  19. package/dist/esm/spec/features/matchers/toHaveUnchecked.spec.js +19 -0
  20. package/dist/esm/spec/features/matchers/toHaveUrl.spec.js +13 -0
  21. package/dist/esm/spec/features/matchers/toMatchTextContent.spec.js +12 -0
  22. package/dist/esm/spec/features/matchers/toNotMatchSelector.spec.js +12 -0
  23. package/dist/esm/spec/features/matchers/toNotMatchTextContent.spec.js +12 -0
  24. package/dist/esm/spec/features/matchers/toUncheck.spec.js +20 -0
  25. package/dist/esm/spec/features/setup/globalSetup.js +8 -0
  26. package/dist/esm/spec/features/setup/hooks.js +36 -0
  27. package/dist/esm/spec/features/uncheck.spec.js +20 -0
  28. package/dist/esm/spec/features/vite.config.js +16 -0
  29. package/dist/esm/spec/helpers/sleep.js +7 -0
  30. package/dist/esm/spec/unit/setup/globalSetup.js +3 -0
  31. package/dist/esm/spec/unit/setup/hooks.js +16 -0
  32. package/dist/esm/spec/unit/specRequest/delete.spec.js +45 -0
  33. package/dist/esm/spec/unit/specRequest/get.spec.js +45 -0
  34. package/dist/esm/spec/unit/specRequest/patch.spec.js +45 -0
  35. package/dist/esm/spec/unit/specRequest/post.spec.js +45 -0
  36. package/dist/esm/spec/unit/specRequest/put.spec.js +45 -0
  37. package/dist/esm/spec/unit/specRequest/session.spec.js +29 -0
  38. package/dist/esm/spec/unit/vite.config.js +15 -0
  39. package/dist/esm/src/feature/helpers/providePuppeteerViteMatchers.js +8 -5
  40. package/dist/esm/src/feature/internal/isPuppeteerPage.js +1 -0
  41. package/dist/esm/src/feature/internal/requirePuppeteerPage.js +1 -0
  42. package/dist/esm/src/feature/matchers/toCheck.js +7 -7
  43. package/dist/esm/src/feature/matchers/toClick.js +2 -2
  44. package/dist/esm/src/feature/matchers/toClickButton.js +2 -2
  45. package/dist/esm/src/feature/matchers/toClickLink.js +2 -2
  46. package/dist/esm/src/feature/matchers/toClickSelector.js +2 -2
  47. package/dist/esm/src/feature/matchers/toHaveChecked.js +13 -3
  48. package/dist/esm/src/feature/matchers/toHavePath.js +23 -4
  49. package/dist/esm/src/feature/matchers/toHaveUnchecked.js +15 -5
  50. package/dist/esm/src/feature/matchers/toHaveUrl.js +21 -9
  51. package/dist/esm/src/feature/matchers/toMatchTextContent.js +3 -3
  52. package/dist/esm/src/feature/matchers/toNotMatchTextContent.js +2 -1
  53. package/dist/esm/src/feature/matchers/toUncheck.js +12 -8
  54. package/dist/esm/src/unit/SpecRequest.js +14 -9
  55. package/dist/esm/src/unit/SpecSession.js +1 -1
  56. package/dist/esm/src/unit/createPsychicServer.js +6 -0
  57. package/dist/esm/src/unit/supersession.js +19 -3
  58. package/dist/esm/test-app/client/src/api/openapi.js +5 -0
  59. package/dist/esm/test-app/spec/factories/UserFactory.js +6 -0
  60. package/dist/esm/test-app/spec/unit/models/User.spec.js +4 -0
  61. package/dist/esm/test-app/src/app/controllers/ApplicationController.js +7 -0
  62. package/dist/esm/test-app/src/app/controllers/SpecRequestController.js +41 -0
  63. package/dist/esm/test-app/src/app/helpers/importAll.js +3 -0
  64. package/dist/esm/test-app/src/app/helpers/importDefault.js +3 -0
  65. package/dist/esm/test-app/src/app/helpers/srcPath.js +26 -0
  66. package/dist/esm/test-app/src/app/models/ApplicationModel.js +10 -0
  67. package/dist/esm/test-app/src/app/models/User.js +16 -0
  68. package/dist/esm/test-app/src/app/serializers/UserSerializer.js +76 -0
  69. package/dist/esm/test-app/src/cli/helpers/initializePsychicApplication.js +7 -0
  70. package/dist/esm/test-app/src/cli/index.js +16 -0
  71. package/dist/esm/test-app/src/conf/app.js +39 -0
  72. package/dist/esm/test-app/src/conf/dream.js +31 -0
  73. package/dist/esm/test-app/src/conf/global.js +1 -0
  74. package/dist/esm/test-app/src/conf/inflections.js +4 -0
  75. package/dist/esm/test-app/src/conf/loadEnv.js +3 -0
  76. package/dist/esm/test-app/src/conf/repl.js +10 -0
  77. package/dist/esm/test-app/src/conf/routeTypes.js +1 -0
  78. package/dist/esm/test-app/src/conf/routes.js +11 -0
  79. package/dist/esm/test-app/src/db/migrations/1737751561543-user.js +14 -0
  80. package/dist/esm/test-app/src/db/seed.js +1 -0
  81. package/dist/esm/test-app/src/types/db.js +3 -0
  82. package/dist/esm/test-app/src/types/dream.js +120 -0
  83. package/dist/esm/test-app/src/types/psychic.js +6 -0
  84. package/dist/types/spec/features/check.spec.d.ts +1 -0
  85. package/dist/types/spec/features/click.spec.d.ts +1 -0
  86. package/dist/types/spec/features/clickButton.spec.d.ts +1 -0
  87. package/dist/types/spec/features/clickLink.spec.d.ts +1 -0
  88. package/dist/types/spec/features/clickSelector.spec.d.ts +1 -0
  89. package/dist/types/spec/features/fillIn.spec.d.ts +1 -0
  90. package/dist/types/spec/features/helpers/getPage.d.ts +2 -0
  91. package/dist/types/spec/features/matchers/toCheck.spec.d.ts +1 -0
  92. package/dist/types/spec/features/matchers/toClick.spec.d.ts +1 -0
  93. package/dist/types/spec/features/matchers/toClickButton.spec.d.ts +1 -0
  94. package/dist/types/spec/features/matchers/toClickLink.spec.d.ts +1 -0
  95. package/dist/types/spec/features/matchers/toClickSelector.spec.d.ts +1 -0
  96. package/dist/types/spec/features/matchers/toFill.spec.d.ts +1 -0
  97. package/dist/types/spec/features/matchers/toHaveChecked.spec.d.ts +1 -0
  98. package/dist/types/spec/features/matchers/toHaveLink.spec.d.ts +1 -0
  99. package/dist/types/spec/features/matchers/toHavePath.spec.d.ts +1 -0
  100. package/dist/types/spec/features/matchers/toHaveSelector.spec.d.ts +1 -0
  101. package/dist/types/spec/features/matchers/toHaveUnchecked.spec.d.ts +1 -0
  102. package/dist/types/spec/features/matchers/toHaveUrl.spec.d.ts +1 -0
  103. package/dist/types/spec/features/matchers/toMatchTextContent.spec.d.ts +1 -0
  104. package/dist/types/spec/features/matchers/toNotMatchSelector.spec.d.ts +1 -0
  105. package/dist/types/spec/features/matchers/toNotMatchTextContent.spec.d.ts +1 -0
  106. package/dist/types/spec/features/matchers/toUncheck.spec.d.ts +1 -0
  107. package/dist/types/spec/features/setup/globalSetup.d.ts +3 -0
  108. package/dist/types/spec/features/setup/hooks.d.ts +1 -0
  109. package/dist/types/spec/features/uncheck.spec.d.ts +1 -0
  110. package/dist/types/spec/features/vite.config.d.ts +2 -0
  111. package/dist/types/spec/helpers/sleep.d.ts +1 -0
  112. package/dist/types/spec/unit/setup/globalSetup.d.ts +3 -0
  113. package/dist/types/spec/unit/setup/hooks.d.ts +1 -0
  114. package/dist/types/spec/unit/specRequest/delete.spec.d.ts +1 -0
  115. package/dist/types/spec/unit/specRequest/get.spec.d.ts +1 -0
  116. package/dist/types/spec/unit/specRequest/patch.spec.d.ts +1 -0
  117. package/dist/types/spec/unit/specRequest/post.spec.d.ts +1 -0
  118. package/dist/types/spec/unit/specRequest/put.spec.d.ts +1 -0
  119. package/dist/types/spec/unit/specRequest/session.spec.d.ts +1 -0
  120. package/dist/types/spec/unit/vite.config.d.ts +2 -0
  121. package/dist/types/src/feature/matchers/toCheck.d.ts +1 -4
  122. package/dist/types/src/feature/matchers/toClick.d.ts +1 -4
  123. package/dist/types/src/feature/matchers/toClickButton.d.ts +1 -4
  124. package/dist/types/src/feature/matchers/toClickLink.d.ts +1 -4
  125. package/dist/types/src/feature/matchers/toClickSelector.d.ts +1 -4
  126. package/dist/types/src/feature/matchers/toFill.d.ts +1 -1
  127. package/dist/types/src/feature/matchers/toHaveChecked.d.ts +0 -3
  128. package/dist/types/src/feature/matchers/toHavePath.d.ts +5 -2
  129. package/dist/types/src/feature/matchers/toHaveUrl.d.ts +3 -3
  130. package/dist/types/src/feature/matchers/toMatchTextContent.d.ts +1 -1
  131. package/dist/types/src/feature/matchers/toNotMatchTextContent.d.ts +2 -2
  132. package/dist/types/src/feature/matchers/toUncheck.d.ts +0 -6
  133. package/dist/types/src/index.d.ts +4 -4
  134. package/dist/types/src/unit/SpecRequest.d.ts +3 -3
  135. package/dist/types/test-app/client/src/api/openapi.d.ts +81 -0
  136. package/dist/types/test-app/spec/factories/UserFactory.d.ts +3 -0
  137. package/dist/types/test-app/spec/unit/models/User.spec.d.ts +1 -0
  138. package/dist/types/test-app/src/app/controllers/ApplicationController.d.ts +6 -0
  139. package/dist/types/test-app/src/app/controllers/SpecRequestController.d.ts +10 -0
  140. package/dist/types/test-app/src/app/helpers/importAll.d.ts +1 -0
  141. package/dist/types/test-app/src/app/helpers/importDefault.d.ts +1 -0
  142. package/dist/types/test-app/src/app/helpers/srcPath.d.ts +1 -0
  143. package/dist/types/test-app/src/app/models/ApplicationModel.d.ts +68 -0
  144. package/dist/types/test-app/src/app/models/User.d.ts +10 -0
  145. package/dist/types/test-app/src/app/serializers/UserSerializer.d.ts +8 -0
  146. package/dist/types/test-app/src/cli/helpers/initializePsychicApplication.d.ts +3 -0
  147. package/dist/types/test-app/src/cli/index.d.ts +2 -0
  148. package/dist/types/test-app/src/conf/app.d.ts +3 -0
  149. package/dist/types/test-app/src/conf/dream.d.ts +2 -0
  150. package/dist/types/test-app/src/conf/global.d.ts +1 -0
  151. package/dist/types/test-app/src/conf/inflections.d.ts +1 -0
  152. package/dist/types/test-app/src/conf/loadEnv.d.ts +2 -0
  153. package/dist/types/test-app/src/conf/repl.d.ts +3 -0
  154. package/dist/types/test-app/src/conf/routeTypes.d.ts +1 -0
  155. package/dist/types/test-app/src/conf/routes.d.ts +3 -0
  156. package/dist/types/test-app/src/db/migrations/1737751561543-user.d.ts +3 -0
  157. package/dist/types/test-app/src/db/seed.d.ts +1 -0
  158. package/dist/types/test-app/src/types/db.d.ts +22 -0
  159. package/dist/types/test-app/src/types/dream.d.ts +65 -0
  160. package/dist/types/test-app/src/types/psychic.d.ts +4 -0
  161. package/package.json +25 -3
  162. package/src/feature/helpers/launchDevServer.ts +1 -1
  163. package/src/feature/helpers/providePuppeteerViteMatchers.ts +16 -5
  164. package/src/feature/internal/isPuppeteerPage.ts +2 -1
  165. package/src/feature/internal/requirePuppeteerPage.ts +1 -0
  166. package/src/feature/matchers/toCheck.ts +8 -8
  167. package/src/feature/matchers/toClick.ts +2 -2
  168. package/src/feature/matchers/toClickButton.ts +2 -2
  169. package/src/feature/matchers/toClickLink.ts +2 -2
  170. package/src/feature/matchers/toClickSelector.ts +3 -2
  171. package/src/feature/matchers/toFill.ts +1 -1
  172. package/src/feature/matchers/toHaveChecked.ts +15 -6
  173. package/src/feature/matchers/toHavePath.ts +32 -8
  174. package/src/feature/matchers/toHaveUnchecked.ts +17 -8
  175. package/src/feature/matchers/toHaveUrl.ts +31 -15
  176. package/src/feature/matchers/toMatchTextContent.ts +6 -3
  177. package/src/feature/matchers/toNotMatchTextContent.ts +4 -2
  178. package/src/feature/matchers/toUncheck.ts +12 -8
  179. package/src/index.ts +27 -4
  180. package/src/unit/SpecRequest.ts +15 -14
  181. package/src/unit/SpecSession.ts +1 -1
  182. package/src/unit/createPsychicServer.ts +7 -0
  183. package/src/unit/supersession.ts +15 -1
  184. package/tsconfig.json +1 -1
  185. package/dist/esm/src/feature/internal/evaluationFailure.js +0 -6
  186. package/dist/esm/src/feature/internal/evaluationSuccess.js +0 -6
  187. package/dist/esm/src/feature/internal/matchFailure.js +0 -6
  188. package/dist/esm/src/feature/internal/matchSuccess.js +0 -6
  189. package/dist/types/src/feature/internal/evaluationFailure.d.ts +0 -4
  190. package/dist/types/src/feature/internal/evaluationSuccess.d.ts +0 -4
  191. package/dist/types/src/feature/internal/matchFailure.d.ts +0 -4
  192. package/dist/types/src/feature/internal/matchSuccess.d.ts +0 -4
  193. package/src/feature/internal/evaluationFailure.ts +0 -6
  194. package/src/feature/internal/evaluationSuccess.ts +0 -6
  195. package/src/feature/internal/matchFailure.ts +0 -6
  196. package/src/feature/internal/matchSuccess.ts +0 -6
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,15 @@
1
+ describe('check', () => {
2
+ it('succeeds when label for checkbox is found', async () => {
3
+ await check('My checkbox');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ const inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
6
+ expect(inputValue).toBe(true);
7
+ });
8
+ it('fails when the selector is not found', async () => {
9
+ await check('My checkbox', { timeout: 500 });
10
+ await expect(async () => {
11
+ await check('not found checkbox', { timeout: 500 });
12
+ }).rejects.toThrow();
13
+ });
14
+ });
15
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('click', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await click('My div');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await click('My div', { timeout: 500 });
7
+ await expect(async () => {
8
+ await click('Not found div', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('clickButton', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await clickButton('My button');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await clickButton('My button', { timeout: 500 });
7
+ await expect(async () => {
8
+ await clickButton('Not found button', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('clickLink', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await clickLink('My link');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await clickLink('My link', { timeout: 500 });
7
+ await expect(async () => {
8
+ await clickLink('Not found link', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('clickSelector', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await clickSelector('#my-button');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await clickSelector('#my-button', { timeout: 500 });
7
+ await expect(async () => {
8
+ await clickSelector('#not-found', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,15 @@
1
+ describe('fillIn', () => {
2
+ it('succeeds when the input is fillable', async () => {
3
+ await fillIn('#my-input', 'hello');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ const inputValue = await page.$eval('#my-input', input => input.value).catch(() => null);
6
+ expect(inputValue).toEqual('hello');
7
+ });
8
+ it('fails when the selector is not found', async () => {
9
+ await fillIn('#my-input', 'hello world', { timeout: 500 });
10
+ await expect(async () => {
11
+ await fillIn('#not-found-input', 'hello world', { timeout: 500 });
12
+ }).rejects.toThrow();
13
+ });
14
+ });
15
+ export {};
@@ -0,0 +1,10 @@
1
+ import { launchPage } from '../../../src/index.js';
2
+ let page;
3
+ export default async function getPage(opts) {
4
+ if (!page) {
5
+ page = await launchPage({ headless: process.env.HEADLESS !== '0', timeout: 20000, ...opts });
6
+ // set the browser dimensions prior to running specs
7
+ await page.setViewport({ width: 1200, height: 800 });
8
+ }
9
+ return page;
10
+ }
@@ -0,0 +1,15 @@
1
+ describe('toCheck', () => {
2
+ it('succeeds when label for checkbox is found', async () => {
3
+ await expect(page).toCheck('My checkbox');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ const inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
6
+ expect(inputValue).toBe(true);
7
+ });
8
+ it('fails when the selector is not found', async () => {
9
+ await expect(page).toCheck('My checkbox', { timeout: 500 });
10
+ await expect(async () => {
11
+ await expect(page).toCheck('not found checkbox', { timeout: 500 });
12
+ }).rejects.toThrow();
13
+ });
14
+ });
15
+ export {};
@@ -0,0 +1,13 @@
1
+ describe('toClick', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await expect(page).toClick('My div');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await click('My div', { timeout: 500 });
7
+ await expect(page).toClick('My div', { timeout: 500 });
8
+ await expect(async () => {
9
+ await expect(page).toClick('Not found div', { timeout: 500 });
10
+ }).rejects.toThrow();
11
+ });
12
+ });
13
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toClickButton', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await expect(page).toClickButton('My button');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toClickButton('My button', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toClickButton('Not found button', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('clickLink', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await expect(page).toClickLink('My link');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toClickLink('My link', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toClickLink('Not found link', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toClickSelector', () => {
2
+ it('succeeds when the selector is found', async () => {
3
+ await expect(page).toClickSelector('#my-button');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toClickSelector('#my-button', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toClickSelector('#not-found', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,15 @@
1
+ describe('toFill', () => {
2
+ it('succeeds when the input is fillable', async () => {
3
+ await expect(page).toFill('#my-input', 'hello');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ const inputValue = await page.$eval('#my-input', input => input.value).catch(() => null);
6
+ expect(inputValue).toEqual('hello');
7
+ });
8
+ it('fails when the selector is not found', async () => {
9
+ await expect(page).toFill('#my-input', 'hello world', { timeout: 500 });
10
+ await expect(async () => {
11
+ await expect(page).toFill('#not-found-input', 'hello world', { timeout: 500 });
12
+ }).rejects.toThrow();
13
+ });
14
+ });
15
+ export {};
@@ -0,0 +1,13 @@
1
+ describe('toHaveChecked', () => {
2
+ it('succeeds when label for checkbox is found', async () => {
3
+ await check('My checkbox');
4
+ await expect(page).toHaveChecked('My checkbox');
5
+ });
6
+ it('fails when the selector is not found', async () => {
7
+ await check('My checkbox', { timeout: 500 });
8
+ await expect(async () => {
9
+ await expect(page).toHaveChecked('not found checkbox', { timeout: 500 });
10
+ }).rejects.toThrow();
11
+ });
12
+ });
13
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toHaveLink', () => {
2
+ it('succeeds when link with text is found', async () => {
3
+ await expect(page).toHaveLink('My link');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toHaveLink('My link', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toHaveLink('not found link', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toHavePath', () => {
2
+ it('succeeds when the path is correct', async () => {
3
+ await expect(page).toHavePath('/');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toHavePath('/', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toHavePath('/not-found', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toHavePath', () => {
2
+ it('succeeds when the path is correct', async () => {
3
+ await expect(page).toHaveSelector('#my-button');
4
+ });
5
+ it('fails when the selector is not found', async () => {
6
+ await expect(page).toHaveSelector('#my-button', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toHaveSelector('#not-found-button', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,19 @@
1
+ describe('toHaveUnchecked', () => {
2
+ it('succeeds when the input is unchecked', async () => {
3
+ await expect(page).toHaveUnchecked('My checkbox');
4
+ });
5
+ it('fails when the input is checked', async () => {
6
+ await expect(page).toHaveUnchecked('My checkbox', { timeout: 500 });
7
+ await expect(async () => {
8
+ await check('My checkbox');
9
+ await expect(page).toHaveUnchecked('My checkbox', { timeout: 500 });
10
+ }).rejects.toThrow();
11
+ });
12
+ it('fails when the input is not found', async () => {
13
+ await check('My checkbox', { timeout: 500 });
14
+ await expect(async () => {
15
+ await expect(page).toHaveUnchecked('not found checkbox', { timeout: 500 });
16
+ }).rejects.toThrow();
17
+ });
18
+ });
19
+ export {};
@@ -0,0 +1,13 @@
1
+ describe('toHaveUrl', () => {
2
+ it('succeeds when the page matches the url', async () => {
3
+ await expect(page).toHaveUrl('http://localhost:3000/');
4
+ await expect(page).toHaveUrl('http://localhost:3000');
5
+ });
6
+ it('fails when the page does not match the url', async () => {
7
+ await expect(page).toHaveUrl('http://localhost:3000/', { timeout: 500 });
8
+ await expect(async () => {
9
+ await expect(page).toHaveUrl('http://localhost:3000/not-here', { timeout: 500 });
10
+ }).rejects.toThrow();
11
+ });
12
+ });
13
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toMatchTextContent', () => {
2
+ it('succeeds when the page matches the content', async () => {
3
+ await expect(page).toMatchTextContent('My div');
4
+ });
5
+ it('fails when the page does not match the content', async () => {
6
+ await expect(page).toMatchTextContent('My div', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toMatchTextContent('not found div', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toNotHaveSelector', () => {
2
+ it('succeeds when the page does not match the selector', async () => {
3
+ await expect(page).toNotHaveSelector('#not-found-selector', { timeout: 300 });
4
+ });
5
+ it('fails when the page does match the selector', async () => {
6
+ await expect(page).toNotHaveSelector('#not-found-selector', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toNotHaveSelector('#my-div', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('toNotMatchTextContent', () => {
2
+ it('succeeds when the page does not match the content', async () => {
3
+ await expect(page).toNotMatchTextContent('not found div', { timeout: 300 });
4
+ });
5
+ it('fails when the page does match the content', async () => {
6
+ await expect(page).toNotMatchTextContent('not found div', { timeout: 500 });
7
+ await expect(async () => {
8
+ await expect(page).toNotMatchTextContent('My div', { timeout: 500 });
9
+ }).rejects.toThrow();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,20 @@
1
+ describe('uncheck', () => {
2
+ it('succeeds when label for checkbox is found', async () => {
3
+ await check('My checkbox');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ let inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
6
+ expect(inputValue).toBe(true);
7
+ await expect(page).toUncheck('My checkbox');
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
9
+ inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
10
+ expect(inputValue).toBe(false);
11
+ });
12
+ it('fails when the selector is not found', async () => {
13
+ await check('My checkbox');
14
+ await expect(page).toUncheck('My checkbox', { timeout: 500 });
15
+ await expect(async () => {
16
+ await expect(page).toUncheck('not found checkbox', { timeout: 500 });
17
+ }).rejects.toThrow();
18
+ });
19
+ });
20
+ export {};
@@ -0,0 +1,8 @@
1
+ import '../../../test-app/src/conf/loadEnv.js';
2
+ import { PsychicDevtools } from '@rvoh/psychic';
3
+ export async function setup() {
4
+ await PsychicDevtools.launchDevServer('client', { port: 3000, cmd: 'yarn client:fspec' });
5
+ }
6
+ export function teardown() {
7
+ PsychicDevtools.stopDevServers();
8
+ }
@@ -0,0 +1,36 @@
1
+ import { DreamApplication } from '@rvoh/dream';
2
+ import { provideDreamViteMatchers, truncate } from '@rvoh/dream-spec-helpers';
3
+ import { PsychicServer } from '@rvoh/psychic';
4
+ import { providePuppeteerViteMatchers } from '../../../src/index.js';
5
+ import initializePsychicApplication from '../../../test-app/src/cli/helpers/initializePsychicApplication.js';
6
+ import getPage from '../helpers/getPage.js';
7
+ provideDreamViteMatchers();
8
+ providePuppeteerViteMatchers();
9
+ global.context = describe;
10
+ global.jest = vi;
11
+ let server;
12
+ beforeAll(async () => {
13
+ try {
14
+ await initializePsychicApplication();
15
+ }
16
+ catch (err) {
17
+ console.error(err);
18
+ throw err;
19
+ }
20
+ server = new PsychicServer();
21
+ await server.start(parseInt(process.env.DEV_SERVER_PORT || '7778'));
22
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
23
+ if (!global.page) {
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
25
+ ;
26
+ global.page = await getPage();
27
+ }
28
+ });
29
+ beforeEach(async () => {
30
+ await truncate(DreamApplication);
31
+ await visit('/');
32
+ await expect(page).toMatchTextContent('My div');
33
+ });
34
+ afterAll(async () => {
35
+ await server.stop();
36
+ });
@@ -0,0 +1,20 @@
1
+ describe('uncheck', () => {
2
+ it('succeeds when label for checkbox is found', async () => {
3
+ await check('My checkbox');
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
5
+ let inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
6
+ expect(inputValue).toBe(true);
7
+ await uncheck('My checkbox');
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
9
+ inputValue = await page.$eval('#my-checkbox', input => input.checked).catch(() => null);
10
+ expect(inputValue).toBe(false);
11
+ });
12
+ it('fails when the selector is not found', async () => {
13
+ await check('My checkbox');
14
+ await uncheck('My checkbox', { timeout: 500 });
15
+ await expect(async () => {
16
+ await uncheck('not found checkbox', { timeout: 500 });
17
+ }).rejects.toThrow();
18
+ });
19
+ });
20
+ export {};
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ dir: './spec/features',
5
+ globals: true,
6
+ setupFiles: ['luxon-jest-matchers', './spec/features/setup/hooks.js'],
7
+ fileParallelism: false,
8
+ maxConcurrency: 1,
9
+ maxWorkers: 1,
10
+ minWorkers: 1,
11
+ mockReset: true,
12
+ watch: false,
13
+ printConsoleTrace: true,
14
+ globalSetup: './spec/features/setup/globalSetup.js',
15
+ },
16
+ });
@@ -0,0 +1,7 @@
1
+ export default async function sleep(ms) {
2
+ return await new Promise(accept => {
3
+ setTimeout(() => {
4
+ accept(undefined);
5
+ }, ms);
6
+ });
7
+ }
@@ -0,0 +1,3 @@
1
+ import '../../../test-app/src/conf/global.js';
2
+ export async function setup() { }
3
+ export async function teardown() { }
@@ -0,0 +1,16 @@
1
+ import { DreamApplication } from '@rvoh/dream';
2
+ import { provideDreamViteMatchers, truncate } from '@rvoh/dream-spec-helpers';
3
+ import initializePsychicApplication from '../../../test-app/src/cli/helpers/initializePsychicApplication.js';
4
+ provideDreamViteMatchers();
5
+ global.context = describe;
6
+ global.jest = vi;
7
+ beforeEach(async () => {
8
+ try {
9
+ await initializePsychicApplication();
10
+ }
11
+ catch (error) {
12
+ console.error(error);
13
+ throw error;
14
+ }
15
+ await truncate(DreamApplication);
16
+ });
@@ -0,0 +1,45 @@
1
+ import { PsychicServer } from '@rvoh/psychic';
2
+ import { specRequest as request } from '../../../src/index.js';
3
+ describe('specRequest#delete', () => {
4
+ beforeEach(async () => {
5
+ await request.init(PsychicServer);
6
+ });
7
+ it('issues a delete request to a controller endpoint, passing when the status matches', async () => {
8
+ const res = await request.delete(`/spec-request/delete-test`, 200, {
9
+ data: {
10
+ a: 'a',
11
+ b: 'b',
12
+ },
13
+ headers: {
14
+ headerA: 'A',
15
+ headerB: 'B',
16
+ },
17
+ });
18
+ expect(res.body).toEqual({
19
+ body: { a: 'a', b: 'b' },
20
+ headers: expect.objectContaining({
21
+ headera: 'A',
22
+ headerb: 'B',
23
+ }),
24
+ });
25
+ });
26
+ it('fails when the status does not match', async () => {
27
+ await expect(async () => {
28
+ await request.delete(`/spec-request/delete-test`, 201);
29
+ }).rejects.toThrow();
30
+ });
31
+ context('with an error status', () => {
32
+ it('passes when the error status is expected', async () => {
33
+ await request.delete(`/spec-request/delete-test`, 400, {
34
+ data: { throw400: true },
35
+ });
36
+ });
37
+ it('fails when the error status is not expected', async () => {
38
+ await expect(async () => {
39
+ await request.delete(`/spec-request/delete-test`, 200, {
40
+ data: { throw400: true },
41
+ });
42
+ }).rejects.toThrow();
43
+ });
44
+ });
45
+ });
@@ -0,0 +1,45 @@
1
+ import { PsychicServer } from '@rvoh/psychic';
2
+ import { specRequest as request } from '../../../src/index.js';
3
+ describe('specRequest#get', () => {
4
+ beforeEach(async () => {
5
+ await request.init(PsychicServer);
6
+ });
7
+ it('issues a get request to a controller endpoint, passing when the status matches', async () => {
8
+ const res = await request.get(`/spec-request/get-test`, 200, {
9
+ query: {
10
+ a: 'a',
11
+ b: 'b',
12
+ },
13
+ headers: {
14
+ headerA: 'A',
15
+ headerB: 'B',
16
+ },
17
+ });
18
+ expect(res.body).toEqual({
19
+ query: { a: 'a', b: 'b' },
20
+ headers: expect.objectContaining({
21
+ headera: 'A',
22
+ headerb: 'B',
23
+ }),
24
+ });
25
+ });
26
+ it('fails when the status does not match', async () => {
27
+ await expect(async () => {
28
+ await request.get(`/spec-request/get-test`, 201);
29
+ }).rejects.toThrow();
30
+ });
31
+ context('with an error status', () => {
32
+ it('passes when the error status is expected', async () => {
33
+ await request.get(`/spec-request/get-test`, 400, {
34
+ query: { throw400: true },
35
+ });
36
+ });
37
+ it('fails when the error status is not expected', async () => {
38
+ await expect(async () => {
39
+ await request.get(`/spec-request/get-test`, 200, {
40
+ query: { throw400: true },
41
+ });
42
+ }).rejects.toThrow();
43
+ });
44
+ });
45
+ });
@@ -0,0 +1,45 @@
1
+ import { PsychicServer } from '@rvoh/psychic';
2
+ import { specRequest as request } from '../../../src/index.js';
3
+ describe('specRequest#patch', () => {
4
+ beforeEach(async () => {
5
+ await request.init(PsychicServer);
6
+ });
7
+ it('issues a patch request to a controller endpoint, passing when the status matches', async () => {
8
+ const res = await request.patch(`/spec-request/patch-test`, 200, {
9
+ data: {
10
+ a: 'a',
11
+ b: 'b',
12
+ },
13
+ headers: {
14
+ headerA: 'A',
15
+ headerB: 'B',
16
+ },
17
+ });
18
+ expect(res.body).toEqual({
19
+ body: { a: 'a', b: 'b' },
20
+ headers: expect.objectContaining({
21
+ headera: 'A',
22
+ headerb: 'B',
23
+ }),
24
+ });
25
+ });
26
+ it('fails when the status does not match', async () => {
27
+ await expect(async () => {
28
+ await request.patch(`/spec-request/patch-test`, 201);
29
+ }).rejects.toThrow();
30
+ });
31
+ context('with an error status', () => {
32
+ it('passes when the error status is expected', async () => {
33
+ await request.patch(`/spec-request/patch-test`, 400, {
34
+ data: { throw400: true },
35
+ });
36
+ });
37
+ it('fails when the error status is not expected', async () => {
38
+ await expect(async () => {
39
+ await request.patch(`/spec-request/patch-test`, 200, {
40
+ data: { throw400: true },
41
+ });
42
+ }).rejects.toThrow();
43
+ });
44
+ });
45
+ });