Skip to content

Commit f68d014

Browse files
committed
add cypress and coverage
Signed-off-by: Steffen Ohrendorf <[email protected]>
1 parent 155bae2 commit f68d014

31 files changed

+10313
-15323
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
.DS_Store
22
node_modules
33
/dist
4-
/coverage
54

65
/tests/e2e/reports/
76
selenium-debug.log
@@ -29,3 +28,10 @@ src/version.json
2928
# IntelliJ
3029
.idea/*
3130
!.idea/icon.svg
31+
32+
# Test files
33+
/coverage
34+
/cypress/screenshots
35+
/cypress/downloads
36+
/.nyc_output
37+
.output.txt

.nycrc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"all": true,
3+
"include": [
4+
"src/**/*.js",
5+
"src/**/*.vue"
6+
],
7+
"exclude": [
8+
"**/*.spec.js",
9+
"**/*.cy.js",
10+
"cypress/**/*.*",
11+
"node_modules/**/*.*"
12+
],
13+
"reporter": [
14+
"lcov",
15+
"text",
16+
"html"
17+
],
18+
"report-dir": "coverage",
19+
"extension": [
20+
".js",
21+
".vue"
22+
],
23+
"check-coverage": false
24+
}

babel.config.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module.exports = {
2-
presets: [
3-
['@vue/babel-preset-jsx'],
4-
],
2+
presets: [['@vue/babel-preset-jsx']],
3+
env: {
4+
test: {
5+
plugins: ['istanbul'],
6+
},
7+
},
58
};

cypress.config.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const { defineConfig } = require('cypress');
2+
const path = require('path');
3+
const fs = require('fs');
4+
5+
module.exports = defineConfig({
6+
component: {
7+
devServer: {
8+
framework: 'vue2',
9+
bundler: 'vite',
10+
viteConfig: (viteConfig) => {
11+
// Use the coverage config if VITE_COVERAGE is true
12+
if (process.env.VITE_COVERAGE === 'true') {
13+
const coverageConfigPath = path.resolve(
14+
__dirname,
15+
'vite.coverage.config.js',
16+
);
17+
if (fs.existsSync(coverageConfigPath)) {
18+
// We can't use dynamic import in CommonJS, so we'll use a workaround
19+
// This will be executed by Vite which supports ESM
20+
return { configFile: coverageConfigPath };
21+
}
22+
}
23+
24+
// Otherwise, add the code coverage support to the existing config
25+
const config = viteConfig || {};
26+
config.optimizeDeps = config.optimizeDeps || {};
27+
config.optimizeDeps.include = config.optimizeDeps.include || [];
28+
config.optimizeDeps.include.push('@cypress/code-coverage/support');
29+
30+
config.resolve = config.resolve || {};
31+
config.resolve.alias = config.resolve.alias || {};
32+
config.resolve.alias['@'] = path.resolve(__dirname, 'src');
33+
34+
return config;
35+
},
36+
},
37+
setupNodeEvents(on, config) {
38+
require('@cypress/code-coverage/task')(on, config);
39+
return config;
40+
},
41+
},
42+
});

cypress/support/component-index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Cypress Component Test</title>
6+
</head>
7+
<body>
8+
<div data-cy-root></div>
9+
</body>
10+
</html>

cypress/support/component.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import '@cypress/code-coverage/support';
2+
import { mount } from '@cypress/vue2';
3+
import Vue from 'vue';
4+
import BootstrapVue from 'bootstrap-vue';
5+
import 'bootstrap/dist/css/bootstrap.css';
6+
import 'bootstrap-vue/dist/bootstrap-vue.css';
7+
8+
import 'font-awesome/css/font-awesome.css';
9+
10+
Vue.use(BootstrapVue);
11+
12+
/**
13+
* Enhanced mount command with common mocks
14+
*
15+
* @param {Object} component - The Vue component to mount
16+
* @param {Object} options - Mount options
17+
* @param {Object} options.mocks - Custom mocks to override defaults
18+
* @param {Object} options.mockCurrentUser - Whether to mock current user (default: true)
19+
* @param {Object} options.mockApi - Whether to mock Vue.prototype.$api (default: false)
20+
*/
21+
Cypress.Commands.add('mount', (component, options = {}) => {
22+
const defaultMocks = {
23+
$t: (key) => key,
24+
$toastr: {
25+
s: cy.stub(),
26+
w: cy.stub(),
27+
e: cy.stub(),
28+
i: cy.stub(),
29+
},
30+
$root: {
31+
$emit: cy.stub(),
32+
},
33+
};
34+
35+
// Add current user mock if needed
36+
if (options.mockCurrentUser !== false) {
37+
const mockCurrentUser = {
38+
username: 'testuser',
39+
fullname: 'Test User',
40+
41+
};
42+
43+
defaultMocks.currentUser = mockCurrentUser;
44+
defaultMocks.$currentUser = mockCurrentUser;
45+
}
46+
47+
// Setup API mocking if requested
48+
if (options.mockApi) {
49+
cy.mockApi();
50+
}
51+
52+
// Merge default mocks with provided mocks
53+
options.mocks = {
54+
...defaultMocks,
55+
...(options.mocks || {}),
56+
};
57+
58+
return mount(component, options);
59+
});
60+
61+
/**
62+
* Custom command to mock Vue.prototype.$api
63+
* Returns the original $api value for cleanup
64+
*/
65+
Cypress.Commands.add('mockApi', () => {
66+
const originalApi = Vue.prototype.$api;
67+
Vue.prototype.$api = {
68+
BASE_URL: 'api',
69+
URL_USER_MANAGED: 'user/managed',
70+
URL_USER_SELF: 'user/self',
71+
URL_ABOUT: 'version',
72+
};
73+
74+
return originalApi;
75+
});
76+
77+
/**
78+
* Custom command to stub window.location
79+
* This avoids the "Cannot redefine property: location" error
80+
* by using a safer approach to mock the location object
81+
*
82+
* @param {Object} locationStub - The location object properties to stub
83+
* @example
84+
* cy.stubWindowLocation({
85+
* origin: 'https://example.com',
86+
* pathname: '/dashboard'
87+
* });
88+
*/
89+
Cypress.Commands.add('stubWindowLocation', (locationStub = {}) => {
90+
const defaultLocation = {
91+
origin: 'https://example.com',
92+
pathname: '/',
93+
search: '',
94+
hash: '',
95+
href: 'https://example.com/',
96+
protocol: 'https:',
97+
host: 'example.com',
98+
hostname: 'example.com',
99+
port: '',
100+
...locationStub,
101+
};
102+
103+
cy.window().then((win) => {
104+
cy.stub(win, 'location').value(defaultLocation);
105+
});
106+
});

0 commit comments

Comments
 (0)