Skip to content

Commit

Permalink
feat: adding ui component tests (#590)
Browse files Browse the repository at this point in the history
* docs: additional cypress + vitest comparison content

* feat: ui testing

* fix: seperate cypress tests

* feat: adding cypress component testing for ui

* chore: share the common deps for global app setup

* spacing

* Update package.json

Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>

* chore: adding OptimizationPersist + PkgConfig to reduce flake

* chore: workaround for unocss hmr

* chore: adding ts-ignore comments

* chore: reordering data-testid

* chore: ts-expect-error

* --allow-empty

* bug: reproduction of failing vite + cypress setup

* chore: adding Vite 2.9.0-beta.3 to cold-start stability issues for UI component tests

* chore: fixing types

* chore: fixing types

* reenabling tests

* adding faker seed back in

* bumping faker version

Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
3 people committed Mar 21, 2022
1 parent 5010439 commit 7952647
Show file tree
Hide file tree
Showing 23 changed files with 822 additions and 39 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -84,3 +84,23 @@ jobs:

- name: Test
run: pnpm run test:ci

test-ui:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install pnpm
uses: pnpm/action-setup@v2.2.1

- name: Set node
uses: actions/setup-node@v2
with:
node-version: 16.x
cache: "pnpm"

- name: Install
run: pnpm i

- name: Test UI
run: pnpm run ui:test
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -12,5 +12,8 @@ dist
.idea
.DS_Store
bench/test/*/*/
cypress/videos
cypress/downloads
cypress/screenshots
docs/public/user-avatars
docs/public/sponsors
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -25,7 +25,8 @@
"test:ci": "cross-env CI=true pnpm -r --stream --filter !@vitest/monorepo --filter !test-fails run test -- --allowOnly",
"typecheck": "tsc --noEmit",
"ui:build": "vite build packages/ui",
"ui:dev": "vite packages/ui"
"ui:dev": "vite packages/ui",
"ui:test": "npm -C packages/ui run test:run"
},
"devDependencies": {
"@antfu/eslint-config": "^0.18.9",
Expand Down Expand Up @@ -56,7 +57,7 @@
"rollup-plugin-esbuild": "^4.8.2",
"rollup-plugin-license": "^2.6.1",
"typescript": "^4.6.2",
"vite": "^2.8.6",
"vite": "2.9.0-beta.3",
"vitepress": "^0.22.3",
"vitest": "workspace:*",
"vue": "^3.2.31"
Expand Down
30 changes: 30 additions & 0 deletions packages/ui/client/components/dashboard/DashboardEntry.cy.tsx
@@ -0,0 +1,30 @@
import faker from '@faker-js/faker'
import DashboardEntry from './DashboardEntry.vue'

const body = () => (<div data-testid="body-content">{ faker.lorem.words(2) }</div>)
const header = () => (<div data-testid="header-content">{ faker.hacker.phrase() }</div>)
const bodySelector = '[data-testid=body-content]'
const headerSelector = '[data-testid=header-content]'
const tailSelector = '[data-testid=tail]'

describe('DashboardEntry', () => {
it('tail is rendered by default', () => {
cy.mount(<DashboardEntry v-slots={{ body, header }}/>)
.get(tailSelector)
.should('exist')
})

it('tail is not shown when true', () => {
cy.mount(<DashboardEntry tail v-slots={{ body, header }}/>)
.get(tailSelector)
.should('not.exist')
})

it('renders the body and header slots', () => {
cy.mount(<DashboardEntry v-slots={{ body, header }}/>)
.get(bodySelector)
.should('be.visible')
.get(headerSelector)
.should('be.visible')
})
})
2 changes: 1 addition & 1 deletion packages/ui/client/components/dashboard/DashboardEntry.vue
Expand Up @@ -12,6 +12,6 @@ withDefaults(defineProps<{ tail?: boolean }>(), { tail: false })
<slot name="header" />
</div>
</div>
<div v-if="!tail" my-2 op50 w-1px bg-current origin-center rotate-15 translate-x-3 />
<div v-if="!tail" data-testid="tail" my-2 op50 w-1px bg-current origin-center rotate-15 translate-x-3 />
</div>
</template>
5 changes: 3 additions & 2 deletions packages/ui/client/components/dashboard/TestFilesEntry.vue
Expand Up @@ -5,13 +5,14 @@ import { filesFailed, filesSnapshotFailed, filesSuccess, time } from '../../comp

<template>
<div
data-testid="test-files-entry"
grid="~ cols-[min-content_1fr_min-content]"
items-center gap="x-2 y-3" p="x4" relative font-light w-80
op80
>
<div i-carbon-document />
<div>Files</div>
<div class="number">
<div class="number" data-testid="num-files">
{{ files.length }}
</div>

Expand Down Expand Up @@ -45,7 +46,7 @@ import { filesFailed, filesSnapshotFailed, filesSuccess, time } from '../../comp

<div i-carbon-timer />
<div>Time</div>
<div class="number">
<div class="number" data-testid="run-time">
{{ time }}
</div>
</div>
Expand Down
10 changes: 5 additions & 5 deletions packages/ui/client/components/dashboard/TestsEntry.vue
Expand Up @@ -14,39 +14,39 @@ const pending = computed(() => {

<template>
<div flex="~ wrap" justify-evenly gap-2 p="x-4" relative>
<DashboardEntry text-green5>
<DashboardEntry text-green5 data-testid="pass-entry">
<template #header>
Pass
</template>
<template #body>
{{ pass }}
</template>
</DashboardEntry>
<DashboardEntry :class="{ 'text-red5': failed, 'op50': !failed }">
<DashboardEntry :class="{ 'text-red5': failed, 'op50': !failed }" data-testid="fail-entry">
<template #header>
Fail
</template>
<template #body>
{{ failed }}
</template>
</DashboardEntry>
<DashboardEntry v-if="skipped" op50>
<DashboardEntry v-if="skipped" op50 data-testid="skipped-entry">
<template #header>
Skip
</template>
<template #body>
{{ skipped }}
</template>
</DashboardEntry>
<DashboardEntry v-if="todo" op50>
<DashboardEntry v-if="todo" op50 data-testid="todo-entry">
<template #header>
Todo
</template>
<template #body>
{{ todo }}
</template>
</DashboardEntry>
<DashboardEntry :tail="true">
<DashboardEntry :tail="true" data-testid="total-entry">
<template #header>
Total
</template>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/client/components/views/ViewConsoleOutput.vue
Expand Up @@ -18,7 +18,7 @@ function getTaskName(id?: string) {
</script>

<template>
<div v-if="logs?.length" h-full class="scrolls" flex flex-col>
<div v-if="logs?.length" h-full class="scrolls" flex flex-col data-testid="logs">
<div v-for="log of logs" :key="log.taskId" font-mono>
<div border="b base" p-4>
<div
Expand Down
1 change: 1 addition & 0 deletions packages/ui/client/components/views/ViewEditor.vue
Expand Up @@ -40,6 +40,7 @@ async function onSave(content: string) {
h-full
v-bind="{ lineNumbers: true }"
:mode="ext"
data-testid="code-mirror"
@save="onSave"
/>
</template>
27 changes: 27 additions & 0 deletions packages/ui/client/global-setup.ts
@@ -0,0 +1,27 @@
/// <reference types="vite-plugin-pages/client" />

import { createRouter as _createRouter, createWebHistory } from 'vue-router'
import FloatingVue, { VTooltip } from 'floating-vue'
import routes from 'virtual:generated-pages'
import 'd3-graph-controller/default.css'
import 'splitpanes/dist/splitpanes.css'
import '@unocss/reset/tailwind.css'
import 'codemirror/lib/codemirror.css'
import 'codemirror-theme-vars/base.css'
import './styles/main.css'
import 'floating-vue/dist/style.css'
import 'uno.css'

export const directives = {
tooltip: VTooltip,
}

FloatingVue.options.instantMove = true
FloatingVue.options.distance = 10

export const createRouter = () => _createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})

export const plugins = [createRouter]
26 changes: 7 additions & 19 deletions packages/ui/client/main.ts
@@ -1,27 +1,15 @@
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import routes from 'virtual:generated-pages'
import FloatingVue, { VTooltip } from 'floating-vue'
import { directives, plugins } from './global-setup'
import App from './App.vue'

import 'd3-graph-controller/default.css'
import 'splitpanes/dist/splitpanes.css'
import '@unocss/reset/tailwind.css'
import 'codemirror/lib/codemirror.css'
import 'codemirror-theme-vars/base.css'
import 'floating-vue/dist/style.css'
import './styles/main.css'
import 'uno.css'

const app = createApp(App)
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,

plugins.forEach((plugin) => {
app.use(plugin)
})
app.use(router)

app.directive('tooltip', VTooltip)
FloatingVue.options.instantMove = true
FloatingVue.options.distance = 10
Object.entries(directives).forEach(([name, directive]) => {
app.directive(name, directive)
})

app.mount('#app')
7 changes: 7 additions & 0 deletions packages/ui/cypress.json
@@ -0,0 +1,7 @@
{
"testFiles": "**/*.cy.{js,ts,jsx,tsx}",
"componentFolder": "client",
"supportFile": "cypress/support/index.ts",
"pluginsFile": "cypress/plugins/index.ts",
"fixturesFolder": false
}
15 changes: 15 additions & 0 deletions packages/ui/cypress/plugins/index.ts
@@ -0,0 +1,15 @@
import path from 'path'
import { startDevServer } from '@cypress/vite-dev-server'

const plugin: Cypress.PluginConfig = (on, config) => {
on('dev-server:start', options => startDevServer({
options,
viteConfig: {
configFile: path.resolve(__dirname, './vite.config.ts'),
},
}))

return config
}

export default plugin
7 changes: 7 additions & 0 deletions packages/ui/cypress/plugins/vite.config.ts
@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { config } from '../../vite.config'

config.plugins?.push(vueJsx())

export default defineConfig(config)
10 changes: 10 additions & 0 deletions packages/ui/cypress/support/index.ts
@@ -0,0 +1,10 @@
import faker from '@faker-js/faker'
import '../../client/global-setup'

import { registerMount } from './mount'

before(() => {
faker.seed(0)
})

registerMount()
31 changes: 31 additions & 0 deletions packages/ui/cypress/support/mount.ts
@@ -0,0 +1,31 @@
import { mount } from '@cypress/vue'
import type { Component } from 'vue'
import { directives, plugins } from '../../client/global-setup'

export const registerMount = () => Cypress.Commands.add(
'mount',
// eslint-disable-next-line @typescript-eslint/no-unused-vars
<C extends Parameters<typeof mount>[0]>(comp: any, options: any = {}) => {
options.global = options.global || {}
options.global.stubs = options.global.stubs || {}
options.global.stubs.transition = false
options.global.plugins = options.global.plugins || []
options.global.directives = directives
plugins?.forEach((pluginFn: () => any) => {
options?.global?.plugins?.push(pluginFn())
})

return mount(comp, options)
},
)

declare global {
namespace Cypress {
interface Chainable {
/**
* Install all vue plugins and globals then mount
*/
mount<Props = any>(comp: Component<Props>, options?: unknown): Cypress.Chainable<any>
}
}
}
39 changes: 35 additions & 4 deletions packages/ui/package.json
Expand Up @@ -28,32 +28,63 @@
"build:node": "rollup -c",
"dev:client": "vite",
"dev": "rollup -c --watch --watch.include=node/**",
"dev:ui": "run-p dev dev:client"
"dev:ui": "run-p dev dev:client",
"test:run": "cypress run-ct",
"test:open": "cypress open-ct"
},
"dependencies": {
"sirv": "^2.0.2"
},
"devDependencies": {
"@cypress/vite-dev-server": "^2.2.2",
"@cypress/vue": "^3.1.0",
"@faker-js/faker": "^6.0.0",
"@types/codemirror": "^5.60.5",
"@types/d3-force": "^3.0.3",
"@types/d3-selection": "^3.0.2",
"@types/ws": "^8.5.3",
"@unocss/reset": "^0.29.5",
"@vitejs/plugin-vue-jsx": "^1.3.3",
"@vitejs/plugin-vue": "^2.2.4",
"@vitest/ws-client": "workspace:*",
"@vueuse/core": "^8.1.2",
"codemirror": "^5.65.2",
"birpc": "^0.1.0",
"codemirror-theme-vars": "^0.1.1",
"codemirror": "^5.65.2",
"cypress": "^9.5.0",
"d3-graph-controller": "^2.2.18",
"flatted": "^3.2.4",
"floating-vue": "^2.0.0-y.0",
"picocolors": "^1.0.0",
"rollup": "^2.70.1",
"splitpanes": "^3.1.1",
"unocss": "^0.29.5",
"unplugin-auto-import": "^0.6.6",
"unplugin-vue-components": "^0.18.3",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1",
"vite-plugin-pages": "^0.22.0",
"vue": "^3.2.31",
"vue-router": "^4.0.14"
"vue-router": "^4.0.14",
"vue": "^3.2.31"
},
"vite": {
"optimizeDeps": {
"include": [
"@cypress/vue",
"@faker-js/faker",
"@vueuse/core",
"birpc",
"codemirror",
"codemirror/addon/display/placeholder",
"codemirror/mode/javascript/javascript",
"codemirror/mode/jsx/jsx",
"codemirror/mode/xml/xml",
"d3-graph-controller",
"flatted",
"floating-vue",
"splitpanes",
"vue-router"
]
}
}
}
3 changes: 3 additions & 0 deletions packages/ui/tsconfig.json
@@ -1,4 +1,7 @@
{
"compilerOptions": {
"jsx": "preserve"
},
"extends": "../../tsconfig.json",
"exclude": ["dist", "node_modules"]
}

0 comments on commit 7952647

Please sign in to comment.