nuxt-spec 0.2.0-alpha.1 → 0.2.0-alpha.2

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.
package/README.md CHANGED
@@ -37,7 +37,7 @@ If you don't want to use the CLI tool, or you want to understand its flow better
37
37
  1) Add following dependency into your `package.json`:
38
38
 
39
39
  ```
40
- "nuxt-spec": "0.2.0-alpha.1"
40
+ "nuxt-spec": "0.2.0-alpha.2"
41
41
  ```
42
42
 
43
43
  2) Add following section into your `nuxt.config.ts`:
@@ -89,7 +89,7 @@ test/
89
89
  └── vitest-unit.test.ts
90
90
  ```
91
91
 
92
- You can use sample files from the [project repository](https://github.com/AloisSeckar/nuxt-spec/tree/v0.2.0-alpha.1/test).
92
+ You can use sample files from the [project repository](https://github.com/AloisSeckar/nuxt-spec/tree/v0.2.0-alpha.2/test).
93
93
 
94
94
  ### Install and execute
95
95
 
@@ -249,11 +249,11 @@ Planned future development:
249
249
  - reason about (not) using Vitest browser mode (or make it optional)
250
250
  - solution for visual regression testing - (currently there is experimental custom solution)
251
251
 
252
- See [CHANGELOG.md](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.1/CHANGELOG.md) for the latest updates and features.
252
+ See [CHANGELOG.md](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.2/CHANGELOG.md) for the latest updates and features.
253
253
 
254
254
  ## Configuration
255
255
 
256
- By default, `nuxt-spec` uses Vitest configuration defined in [`/config/index.mjs`](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.1/config/index.mjs). The configuration is based on [Nuxt team recommendations](https://nuxt.com/docs/4.x/getting-started/testing) and our best judgement.
256
+ By default, `nuxt-spec` uses Vitest configuration defined in [`/config/index.mjs`](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.2/config/index.mjs). The configuration is based on [Nuxt team recommendations](https://nuxt.com/docs/4.x/getting-started/testing) and our best judgement.
257
257
 
258
258
  To add/override your custom config, you can create (or scaffold via CLI tool) a file named `vitest.config.ts` in the root of your project with the following content:
259
259
 
@@ -307,19 +307,19 @@ Nuxt Spec offers couple of utility functions that are exported via `nuxt-spec/ut
307
307
  You can use them in your test files as follows:
308
308
 
309
309
  ```ts
310
- import { compareScrenshot, gotoPage, getDataHtml, getAPIResultHtml, } from 'nuxt-spec/utils'
310
+ import { compareScreenshot, gotoPage, getDataHtml, getAPIResultHtml, } from 'nuxt-spec/utils'
311
311
 
312
312
  // accepts instance of NuxtPage (from @nuxt/test-utils)
313
313
  // takes a screenshot of current viewport and compares it with stored baseline
314
314
  // if screenshot doesn't exist, it will be created as baseline
315
315
  // if screenshots don't match, the method will cause Vitest test to fail
316
- await compareScrenshot(page, 'screenshot.png')
316
+ await compareScreenshot(page, 'screenshot.png')
317
317
 
318
318
  // navigates to given URL and returns the instance of NuxtPage (from @nuxt/test-utils)
319
319
  const page: NuxtPage = await gotoPage('url')
320
320
 
321
321
  // accepts either a URL string or instance of NuxtPage (from @nuxt/test-utils) and a CSS selector
322
- // returns innerHTML of the element matching the selector
322
+ // returns `innerHTML` of the element matching the selector
323
323
  const html: string = await getDataHtml('/', '#test')
324
324
  const html: string = await getDataHtml(page, '#test')
325
325
 
@@ -327,12 +327,13 @@ const html: string = await getDataHtml(page, '#test')
327
327
  // css selector for element that triggers API call when clicked (i.e. button)
328
328
  // fragment of API endpoint URL that should be called (to test the response)
329
329
  // css selector for element where the API response should be rendered (i.e. div)
330
- // returns innerHTML of the element matching the result selector after the API call is made by Playwright runner
331
- const html: string = await getAPIResultHtml('/', '#api-fetch', 'jsonplaceholder.typicode.com/posts', '#api-result')
332
- const html: string = await getAPIResultHtml(page, '#api-fetch', 'jsonplaceholder.typicode.com/posts', '#api-result')
330
+ // returns `innerHTML` of the element matching the result selector after the API call
331
+ // is made by Playwright runner
332
+ const html: string = await getAPIResultHtml('/', '#api-fetch', '/your-api', '#api-result')
333
+ const html: string = await getAPIResultHtml(page, '#api-fetch', '/your-api', '#api-result')
333
334
  ```
334
335
 
335
- For detailed description, see [utils.d.ts](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.1/utils/index.d.ts).
336
+ For detailed description, see [utils.d.ts](https://github.com/AloisSeckar/nuxt-spec/blob/v0.2.0-alpha.2/utils/index.d.ts).
336
337
 
337
338
  ## Contact
338
339
 
package/bin/setup.js CHANGED
@@ -37,7 +37,7 @@ export async function specSetup(autoRun = false) {
37
37
  // add nuxt-spec
38
38
  try {
39
39
  await updateJsonFile('package.json', 'dependencies', {
40
- 'nuxt-spec': '0.2.0-alpha.1',
40
+ 'nuxt-spec': '0.2.0-alpha.2',
41
41
  }, isAutoRun, 'This will add \'nuxt-spec\' dependency to your \'package.json\'. Continue?')
42
42
  } catch (error) {
43
43
  console.error('Error adding \'nuxt-spec\' dependency:\n', error.message)
@@ -107,7 +107,7 @@ export async function specSetup(autoRun = false) {
107
107
  if (pathExists('.npmrc')) {
108
108
  await updateTextFile('.npmrc', ['shamefully-hoist=true'], isAutoRun, 'This will adjust \'.npmrc\' file in your project. Continue?')
109
109
  } else {
110
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/.npmrc',
110
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/.npmrc',
111
111
  '.npmrc', isAutoRun, 'This will add \'.npmrc\' file for your project. Continue?')
112
112
  }
113
113
  } catch (error) {
@@ -117,7 +117,7 @@ export async function specSetup(autoRun = false) {
117
117
 
118
118
  // 4) create vitest.config.ts
119
119
  try {
120
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/config/vitest.config.ts.template',
120
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/config/vitest.config.ts.template',
121
121
  'vitest.config.ts', isAutoRun, 'This will create a new \'vitest.config.ts\' file for your project. Continue?')
122
122
  } catch (error) {
123
123
  console.error('Error setting up \'vitest.config.ts\':\n', error.message)
@@ -155,31 +155,31 @@ export async function specSetup(autoRun = false) {
155
155
  const createSampleTests = isAutoRun || await promptUser('Do you want to create sample tests in \'/test\' folder?')
156
156
  if (createSampleTests) {
157
157
  try {
158
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/test/browser/vitest-browser.test.ts',
158
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/test/browser/vitest-browser.test.ts',
159
159
  'test/browser/vitest-browser.test.ts', true)
160
160
  } catch (error) {
161
161
  console.error('Error setting up \'vitest-browser.test.ts\':\n', error.message)
162
162
  }
163
163
  try {
164
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/test/e2e/nuxt-e2e.test.ts',
164
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/test/e2e/nuxt-e2e.test.ts',
165
165
  'test/e2e/nuxt-e2e.test.ts', true)
166
166
  } catch (error) {
167
167
  console.error('Error setting up \'nuxt-e2e.test.ts\':\n', error.message)
168
168
  }
169
169
  try {
170
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/test/e2e/nuxt-visual.test.ts',
170
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/test/e2e/nuxt-visual.test.ts',
171
171
  'test/e2e/nuxt-visual.test.ts', true)
172
172
  } catch (error) {
173
173
  console.error('Error setting up \'nuxt-visual.test.ts\':\n', error.message)
174
174
  }
175
175
  try {
176
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/test/nuxt/nuxt-unit.test.ts',
176
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/test/nuxt/nuxt-unit.test.ts',
177
177
  'test/nuxt/nuxt-unit.test.ts', true)
178
178
  } catch (error) {
179
179
  console.error('Error setting up \'nuxt-unit.test.ts\':\n', error.message)
180
180
  }
181
181
  try {
182
- await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.1/test/unit/vitest-unit.test.ts',
182
+ await createFileFromWebTemplate('https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v0.2.0-alpha.2/test/unit/vitest-unit.test.ts',
183
183
  'test/unit/vitest-unit.test.ts', true)
184
184
  } catch (error) {
185
185
  console.error('Error setting up \'vitest-unit.test.ts\':\n', error.message)
package/config/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  // based on https://nuxt.com/docs/4.x/getting-started/testing#setup
3
3
  // `projects=false` can be used to suspend the default usage of "projects" in Vitest config
4
4
 
5
- import { mergeConfig } from './merge' // defu-based merge function
5
+ import { mergeConfig } from './merge.js' // defu-based merge function
6
6
  import { defineConfig } from 'vitest/config'
7
7
  import { defineVitestProject } from '@nuxt/test-utils/config'
8
8
  import { playwright } from '@vitest/browser-playwright'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-spec",
3
- "version": "0.2.0-alpha.1",
3
+ "version": "0.2.0-alpha.2",
4
4
  "description": "Test-pack layer for Nuxt Applications",
5
5
  "repository": "github:AloisSeckar/nuxt-spec",
6
6
  "license": "MIT",
@@ -26,7 +26,8 @@
26
26
  "app",
27
27
  "bin",
28
28
  "config",
29
- "public"
29
+ "public",
30
+ "utils"
30
31
  ],
31
32
  "dependencies": {
32
33
  "@nuxt/eslint": "1.15.1",
package/utils/e2e.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { createPage, url } from '@nuxt/test-utils/e2e'
2
+ import type { NuxtPage } from '@nuxt/test-utils'
3
+
4
+ // visit a specified URL and return the page instance for further interaction
5
+ export async function gotoPage(pageName: string): Promise<NuxtPage> {
6
+ const page = await createPage()
7
+ const urlPath = pageName.startsWith('/') ? url(pageName) : url(`/${pageName}`)
8
+ await page.goto(urlPath, { waitUntil: 'hydration' })
9
+ return page
10
+ }
11
+
12
+ // extract HTML content from specified element on a given page
13
+ export async function getDataHtml(page: NuxtPage | string, element: string): Promise<string> {
14
+ const pageInstance = typeof page === 'string' ? await gotoPage(page) : page
15
+ const dataDiv = pageInstance.locator(element)
16
+ return await dataDiv.innerHTML()
17
+ }
18
+
19
+ // execute an API call and extract HTML content from the result
20
+ // (assumes clickable element that triggers the request
21
+ // and separate element for displaying the response)
22
+ export async function getAPIResultHtml(page: NuxtPage | string, triggerElement: string, targetUrl: string, responseElement: string) {
23
+ const pageInstance = typeof page === 'string' ? await gotoPage(page) : page
24
+ await pageInstance.click(triggerElement)
25
+ await pageInstance.waitForResponse(response =>
26
+ response.url().includes(targetUrl) && response.ok(),
27
+ )
28
+ const resultDiv = pageInstance.locator(responseElement)
29
+ return await resultDiv.innerHTML()
30
+ }
@@ -0,0 +1,53 @@
1
+ import type { NuxtPage } from '@nuxt/test-utils'
2
+
3
+ /**
4
+ * Visit a specified URL and return the page instance for further interaction.
5
+ *
6
+ * @param pageName - Path segment appended to the base URL (e.g. `'about'` → `/<about>`)
7
+ * @returns Playwright page instance after navigation and hydration
8
+ */
9
+ export declare function gotoPage(pageName: string): Promise<NuxtPage>
10
+
11
+ /**
12
+ * Extract inner HTML content from a specified element on a given page.
13
+ *
14
+ * @param page - Playwright page instance, or a page name string (will call `gotoPage` internally)
15
+ * @param element - CSS selector identifying the target element
16
+ * @returns The inner HTML of the matched element
17
+ */
18
+ export declare function getDataHtml(page: NuxtPage | string, element: string): Promise<string>
19
+
20
+ /**
21
+ * Execute an API call by clicking a trigger element, wait for a successful
22
+ * response matching the target URL, then extract the inner HTML from the
23
+ * response element.
24
+ *
25
+ * @param page - Playwright page instance, or a page name string (will call `gotoPage` internally)
26
+ * @param triggerElement - CSS selector for the clickable element that triggers the API request
27
+ * @param targetUrl - Substring matched against the response URL to identify the expected API call
28
+ * @param responseElement - CSS selector for the element displaying the API response
29
+ * @returns The inner HTML of the response element
30
+ */
31
+ export declare function getAPIResultHtml(
32
+ page: NuxtPage | string,
33
+ triggerElement: string,
34
+ targetUrl: string,
35
+ responseElement: string,
36
+ ): Promise<string>
37
+
38
+ /**
39
+ * Capture a full-page screenshot and compare it against a stored baseline PNG.
40
+ * When run with `-u` / `--update`, or when no baseline exists yet, the current
41
+ * screenshot is saved as the new baseline.
42
+ *
43
+ * @param page - Playwright page instance obtained from `createPage()`
44
+ * @param fileName - Name of the PNG file used for baseline storage and comparison
45
+ * @param targetDir - Directory for baseline/current screenshots, relative to project root (defaults to `test/e2e`)
46
+ * @returns `true` when the screenshot matches the baseline (or a new baseline was saved)
47
+ * @throws Fails the current Vitest test when a mismatch is detected
48
+ */
49
+ export declare function compareScreenshot(
50
+ page: NuxtPage,
51
+ fileName: string,
52
+ targetDir?: string,
53
+ ): Promise<boolean>
package/utils/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { gotoPage, getDataHtml, getAPIResultHtml } from './e2e'
2
+ import { compareScreenshot } from './screenshot'
3
+
4
+ export {
5
+ compareScreenshot,
6
+ gotoPage,
7
+ getDataHtml,
8
+ getAPIResultHtml,
9
+ }
@@ -0,0 +1,34 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import type { NuxtPage } from '@nuxt/test-utils'
4
+ import { expect } from 'vitest'
5
+
6
+ export async function compareScreenshot(page: NuxtPage, fileName: string, targetDir?: string): Promise<boolean> {
7
+ const dir = resolve(process.cwd(), targetDir ?? 'test/e2e')
8
+ const baselineDir = resolve(dir, '__baseline__')
9
+ const currentDir = resolve(dir, '__current__')
10
+
11
+ // capture full-page screenshot as PNG
12
+ const screenshot = await page.screenshot({ fullPage: true })
13
+ const baselinePath = resolve(baselineDir, fileName)
14
+
15
+ const updating = expect.getState().snapshotState?._updateSnapshot === 'all'
16
+ if (updating || !existsSync(baselinePath)) {
17
+ // save new baseline screenshot
18
+ mkdirSync(baselineDir, { recursive: true })
19
+ writeFileSync(baselinePath, screenshot)
20
+ return true
21
+ }
22
+
23
+ // compare against stored baseline PNG
24
+ const baseline = readFileSync(baselinePath)
25
+ if (!screenshot.equals(baseline)) {
26
+ // save what the test actually saw for debugging
27
+ mkdirSync(currentDir, { recursive: true })
28
+ const actualPath = resolve(currentDir, fileName)
29
+ writeFileSync(actualPath, screenshot)
30
+ expect.fail(`Screenshot mismatch. Actual result saved to: ${actualPath}`)
31
+ }
32
+
33
+ return true
34
+ }
File without changes