Skip to content

Commit

Permalink
feat(npm/vue): expose Test Utils API (#22757)
Browse files Browse the repository at this point in the history
* expose test utils object from cypress/mount

* inline test utils types and rewrite cli/vue/index.d.ts to use inline types

* update readme

* typo and fix comment

* revert accidental change

* revert accidental change
  • Loading branch information
lmiller1990 committed Jul 16, 2022
1 parent 3d07d53 commit 8e07318
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 10 deletions.
1 change: 1 addition & 0 deletions npm/vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This package allows you to use the [Cypress](https://www.cypress.io/) test runne
It uses [Vue Test Utils](https://github.com/vuejs/vue-test-utils) under the hood. This is more of a replacement for node-based testing than it is replacing Vue Test Utils and its API. Instead of running your tests in node (using Jest or Mocha), the Cypress Component Testing Library runs each component in the **real browser** with full power of the Cypress Framework: [live GUI, full API, screen recording, CI support, cross-platform](https://www.cypress.io/features/). One benefit to using Cypress instead of a node-based runner is that limitations of Vue Test Utils in Node (e.g. manually awaiting Vue's internal event loop) are hidden from the user due to Cypress's retry-ability logic.

- If you like using `@testing-library/vue`, you can use `@testing-library/cypress` for the same `findBy`, `queryBy` commands, see one of the examples in the list below
- If you need to access the underlying Vue Test Utils API, you can do so by importing it: `import { VueTestUtils } from 'cypress/vue'`.

### How is this different from @cypress/vue2?
Cypress packages the current version of Vue under @cypress/vue, and older versions under separate package names. Use [@cypress/vue2](cypress-vue2-npm-url) if you're still using vue@2, and this package if you're on vue@3.
Expand Down
23 changes: 23 additions & 0 deletions npm/vue/cypress/component/test-utils-api/TestUtilsApi.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { VueTestUtils, mount } from 'cypress/vue'
import { h } from 'vue'
import TestUtilsApi from './TestUtilsApi.vue'

const greeting = 'This is a globally registered component!'

describe('VueTestUtils API', () => {
before(() => {
VueTestUtils.config.global.components = {
'globally-registered-component': {
setup () {
return () => h('h1', greeting)
},
},
}
})

it('gains access to underlying Vue Test Utils library', () => {
mount(TestUtilsApi)

cy.get('h1').contains(greeting)
})
})
3 changes: 3 additions & 0 deletions npm/vue/cypress/component/test-utils-api/TestUtilsApi.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<globally-registered-component />
</template>
69 changes: 69 additions & 0 deletions npm/vue/inline-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import fs from 'fs-extra'
import globby from 'globby'
import path from 'path'

// We depend on @vue/test-utils and inline this library in the
// @cypress/vue bundle.
// Unfortunately, although rollup can inline libraries like this,
// TypeScript doesn't do the same for d.ts files - it mains imports
// to the original library, which we do not actually ship in the binary.

// This script copies the `d.ts` files into the `dist` directory
// then modifies the `index.d.ts` to reference the copied type definitions
// instead of the ones from the local node_modules directory that we don't
// actually bundle in the binary.

function rewriteSourceForInlineTypes (src: string) {
return src
// Need to modify these lines:
// import type { MountingOptions, VueWrapper } from '@vue/test-utils';
// import * as _VueTestUtils from '@vue/test-utils';
// to
// import type { MountingOptions, VueWrapper } from './@vue/test-utils';
// import * as _VueTestUtils from './@vue/test-utils';
.replaceAll(`'@vue/test-utils';`, `'./@vue/test-utils';`)

// Need to modify this line:
// config: import("@vue/test-utils/config).GlobalConfigOptions;
// to
// config: import("./@vue/test-utils/config").GlobalConfigOptions;
.replaceAll(`@vue/test-utils/dist/config`, `./@vue/test-utils/config`)
}

async function inlineTestUtilsTypes () {
console.log('[npm/vue] Inline type definitions for @vue/test-utils and rewriting source') // eslint-disable-line no-console

// get the directory with the type definitions we want to inline
const vtuDir = path.dirname(require.resolve('@vue/test-utils'))

// grab the type definitions
const typeDefs = await globby('**/*.d.ts', { cwd: vtuDir })

// make a directory for them in npm/vue/dist
const typeDefDir = path.join(__dirname, 'dist', '@vue', 'test-utils')

await fs.mkdir(typeDefDir, { recursive: true })

// copy the type definitions
await Promise.all(
typeDefs.map((tds) => {
const from = path.join(vtuDir, tds)
const to = path.join(typeDefDir, tds)

return fs.copy(from, to, { recursive: true })
}),
)

const cypressVueMainTypeDef = path.join(__dirname, 'dist', 'index.d.ts')

// modify index.d.ts to reference relative type definitions instead of ones from
// node_modules
const updateWithRelativeImports = rewriteSourceForInlineTypes(
await fs.readFile(cypressVueMainTypeDef, 'utf-8'),
)

// rewrite index.d.ts, now modified to point at local type definitions.
await fs.writeFile(cypressVueMainTypeDef, updateWithRelativeImports)
}

inlineTestUtilsTypes()
14 changes: 9 additions & 5 deletions npm/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@
"cy:open": "node ../../scripts/cypress.js open --component --project ${PWD}",
"cy:run": "node ../../scripts/cypress.js run --component --project ${PWD}",
"build": "rimraf dist && rollup -c rollup.config.js",
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
"typecheck": "vue-tsc --noEmit",
"postbuild": "node --require @packages/ts/register ./inline-types.ts && node ../../scripts/sync-exported-npm-with-cli.js",
"typecheck": "yarn tsd && vue-tsc --noEmit",
"test": "yarn cy:run",
"tsd": "yarn build && yarn tsc -p test-tsd/tsconfig.tsd.json",
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
},
"dependencies": {
"@vue/test-utils": "2.0.0-rc.19"
},
"devDependencies": {
"@cypress/code-coverage": "3.8.1",
"@cypress/mount-utils": "0.0.0-development",
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.1.1",
"@vitejs/plugin-vue": "2.3.1",
"@vue/compiler-sfc": "3.2.31",
"@vue/test-utils": "2.0.0-rc.19",
"axios": "0.21.2",
"cypress": "0.0.0-development",
"debug": "^4.3.2",
"globby": "^11.0.1",
"rollup": "^2.38.5",
"rollup-plugin-istanbul": "2.0.1",
"rollup-plugin-typescript2": "^0.29.0",
Expand Down Expand Up @@ -71,6 +71,10 @@
{
"name": "Amir Rustamzadeh",
"social": "@amirrustam"
},
{
"name": "Lachlan Miller",
"social": "@Lachlan19900"
}
],
"module": "dist/cypress-vue.esm-bundler.js",
Expand Down
40 changes: 35 additions & 5 deletions npm/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
/* eslint-disable no-redeclare */
/// <reference types="cypress" />
import { ComponentPublicInstance, VNodeProps, AllowedComponentProps,
ComponentCustomProps, ExtractPropTypes, ExtractDefaultPropTypes,
Component, DefineComponent, FunctionalComponent, ComputedOptions,
MethodOptions, ComponentOptionsMixin, EmitsOptions, ComponentOptionsWithObjectProps, ComponentPropsOptions, ComponentOptionsWithArrayProps, ComponentOptionsWithoutProps } from 'vue'
import { MountingOptions, VueWrapper, mount as VTUmount } from '@vue/test-utils'
import type {
ComponentPublicInstance,
VNodeProps,
AllowedComponentProps,
ComponentCustomProps,
ExtractPropTypes,
ExtractDefaultPropTypes,
DefineComponent,
FunctionalComponent,
ComputedOptions,
MethodOptions,
ComponentOptionsMixin,
EmitsOptions,
ComponentOptionsWithObjectProps,
ComponentPropsOptions,
ComponentOptionsWithArrayProps,
ComponentOptionsWithoutProps,
} from 'vue'
import type { MountingOptions, VueWrapper } from '@vue/test-utils'
import {
injectStylesBeforeElement,
StyleOptions,
getContainerEl,
setupHooks,
} from '@cypress/mount-utils'

import * as _VueTestUtils from '@vue/test-utils'

const {
// We do not expose the `mount` from VueTestUtils, instead, we wrap it and expose a
// Cypress-compatible `mount` API.
mount: VTUmount,
// We do not expose shallowMount. It doesn't make much sense in the context of Cypress.
// It might be useful for people who like to migrate some Test Utils tests to Cypress,
// so if we decide it is useful to expose, just remove the next line, and it will be
// available on the `VueTestUtils` import.
shallowMount,
...VueTestUtils
} = _VueTestUtils

export { VueTestUtils }

const DEFAULT_COMP_NAME = 'unknown'

type GlobalMountOptions = Required<MountingOptions<any>>['global']
Expand Down
4 changes: 4 additions & 0 deletions npm/vue/test-tsd/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function expectType<T>(value: T): void
export function expectError<T>(value: T): void
export function expectAssignable<T, T2 extends T = T>(value: T2): void

17 changes: 17 additions & 0 deletions npm/vue/test-tsd/mount-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expectError, expectType } from './index'
import { mount, VueTestUtils } from '../dist'
import * as VTU from '@vue/test-utils'
import { defineComponent } from 'vue'

const App = defineComponent({
template: `<div />`,
})

// Returns Chainable - not the `mount` function from @vue/test-utils
expectType<Cypress.Chainable>(
mount(App),
)

// Rewritten relative types match those copied from node_modules
// see npm/vue/inline-types.ts for more info.
expectType<typeof VueTestUtils['config']['global']>(VTU['config']['global'])
16 changes: 16 additions & 0 deletions npm/vue/test-tsd/tsconfig.tsd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"strictNullChecks": false
},
"exclude": [
"../src"
],
"include": [
"../dist",
"../test-dts"
]
}

5 comments on commit 8e07318

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 8e07318 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.4.0/linux-x64/develop-8e07318a9f72c3df012be47d500007571165a87e/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 8e07318 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.4.0/darwin-arm64/develop-8e07318a9f72c3df012be47d500007571165a87e/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 8e07318 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.4.0/linux-arm64/develop-8e07318a9f72c3df012be47d500007571165a87e/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 8e07318 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.4.0/darwin-x64/develop-8e07318a9f72c3df012be47d500007571165a87e/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 8e07318 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.4.0/win32-x64/develop-8e07318a9f72c3df012be47d500007571165a87e/cypress.tgz

Please sign in to comment.