@toptal/davinci-qa 6.0.1-alpha-pro-2952-allow-to-disable-type-checking-for-davinci-engine-build-command.22 → 7.0.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.
- package/CHANGELOG.md +18 -0
- package/dist-package/package.json +59 -0
- package/package.json +5 -3
- package/src/commands/end-to-end-tests.js +19 -6
- package/src/commands/end-to-end-tests.test.js +65 -0
- package/src/commands/unit-tests.test.js +164 -0
- package/src/configs/jest/babel-preprocessor.js +3 -0
- package/src/reporters/anvil-results-helper.js +46 -0
- package/src/reporters/anvil-results-helper.test.js +87 -0
- package/src/reporters/cypress-anvil-reporter.js +121 -0
- package/src/reporters/cypress-anvil-reporter.test.js +269 -0
- package/src/reporters/jest-anvil-reporter.js +54 -45
- package/src/reporters/jest-anvil-reporter.test.js +223 -0
- package/src/utils/jest-args-to-cli-converters.test.js +59 -0
- package/src/utils/styled-components-version-check.test.js +78 -0
- package/src/utils/to-jest-cli-arguments.test.js +32 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 7.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#1224](https://github.com/toptal/davinci/pull/1224) [`caf0ee02`](https://github.com/toptal/davinci/commit/caf0ee027107be2acf0315deed33ef89d34f6b69) Thanks [@rafael-anachoreta](https://github.com/rafael-anachoreta)! - ---
|
|
8
|
+
|
|
9
|
+
### Anvil reporter
|
|
10
|
+
|
|
11
|
+
- Add Anvil test mapper
|
|
12
|
+
- Add Anvil reporter to Cypress
|
|
13
|
+
- Update Jest Anvil reporter to use new mapper
|
|
14
|
+
|
|
15
|
+
## 6.0.2
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#1252](https://github.com/toptal/davinci/pull/1252) [`a99253c4`](https://github.com/toptal/davinci/commit/a99253c41eb80f5a31d66766d0efd986d1710bd1) Thanks [@aesqe](https://github.com/aesqe)! - Adds babel-plugin-styled-components to the QA package's Jest config so that the forwardedAs prop is properly working in Jest tests. It also adds the forwardedAs prop to the Skeleton package's react module type.
|
|
20
|
+
|
|
3
21
|
## 6.0.1
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@toptal/davinci-qa",
|
|
3
|
+
"version": "7.0.0",
|
|
4
|
+
"description": "QA package to test your application",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"qa",
|
|
10
|
+
"testing"
|
|
11
|
+
],
|
|
12
|
+
"author": "Toptal",
|
|
13
|
+
"homepage": "https://github.com/toptal/davinci/tree/master/packages/qa#readme",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"bin": {
|
|
16
|
+
"davinci-qa": "./bin/davinci-qa.js"
|
|
17
|
+
},
|
|
18
|
+
"main": "./src/index.js",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/toptal/davinci.git"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build:package": "../../bin/build-package.js",
|
|
25
|
+
"prepublishOnly": "../../bin/prepublish.js",
|
|
26
|
+
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/toptal/davinci/issues"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@babel/core": "^7.14.8",
|
|
33
|
+
"@babel/preset-env": "^7.16.4",
|
|
34
|
+
"@babel/preset-react": "^7.10.4",
|
|
35
|
+
"@babel/preset-typescript": "^7.10.4",
|
|
36
|
+
"@cypress/code-coverage": "^3.9.12",
|
|
37
|
+
"@cypress/webpack-preprocessor": "^5.7.0",
|
|
38
|
+
"@testing-library/jest-dom": "^5.14.1",
|
|
39
|
+
"@testing-library/react": "^12.1.2",
|
|
40
|
+
"@toptal/davinci-cli-shared": "1.5.1",
|
|
41
|
+
"@types/jest": "^27.4.1",
|
|
42
|
+
"babel-jest": "^27.5.1",
|
|
43
|
+
"cypress": "^9.4.1",
|
|
44
|
+
"enhanced-resolve": "^5.9.2",
|
|
45
|
+
"fs-extra": "^10.0.0",
|
|
46
|
+
"glob": "^7.2.0",
|
|
47
|
+
"jest": "^27.5.1",
|
|
48
|
+
"jest-html-reporters": "^3.0.6",
|
|
49
|
+
"jest-junit": "^13.1.0",
|
|
50
|
+
"jest-silent-reporter": "^0.5.0",
|
|
51
|
+
"jest-styled-components": "^7.0.8",
|
|
52
|
+
"jsdom": "^19.0.0",
|
|
53
|
+
"matchmedia-polyfill": "^0.3.2",
|
|
54
|
+
"semver": "^7.3.2"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"mocha": "^9.2.2"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/davinci-qa",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "QA package to test your application",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@cypress/webpack-preprocessor": "^5.7.0",
|
|
38
38
|
"@testing-library/jest-dom": "^5.14.1",
|
|
39
39
|
"@testing-library/react": "^12.1.2",
|
|
40
|
-
"@toptal/davinci-cli-shared": "1.5.
|
|
40
|
+
"@toptal/davinci-cli-shared": "1.5.1",
|
|
41
41
|
"@types/jest": "^27.4.1",
|
|
42
42
|
"babel-jest": "^27.5.1",
|
|
43
43
|
"cypress": "^9.4.1",
|
|
@@ -53,5 +53,7 @@
|
|
|
53
53
|
"matchmedia-polyfill": "^0.3.2",
|
|
54
54
|
"semver": "^7.3.2"
|
|
55
55
|
},
|
|
56
|
-
"
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"mocha": "^9.2.2"
|
|
58
|
+
}
|
|
57
59
|
}
|
|
@@ -6,11 +6,7 @@ const {
|
|
|
6
6
|
} = require('@toptal/davinci-cli-shared')
|
|
7
7
|
|
|
8
8
|
const endToEndTestCommand = ({
|
|
9
|
-
options: {
|
|
10
|
-
open = false,
|
|
11
|
-
baseUrl,
|
|
12
|
-
...cypressOptions
|
|
13
|
-
} = {},
|
|
9
|
+
options: { open = false, baseUrl, anvilTag, ...cypressOptions } = {},
|
|
14
10
|
files: testFiles = []
|
|
15
11
|
}) => {
|
|
16
12
|
print.green('Running end to end tests...')
|
|
@@ -19,6 +15,10 @@ const endToEndTestCommand = ({
|
|
|
19
15
|
'@toptal/davinci-qa',
|
|
20
16
|
'src/configs/cypress.config.json'
|
|
21
17
|
)
|
|
18
|
+
const cypressReporterPath = files.getPackageFilePath(
|
|
19
|
+
'@toptal/davinci-qa',
|
|
20
|
+
'src/reporters/cypress-anvil-reporter.js'
|
|
21
|
+
)
|
|
22
22
|
|
|
23
23
|
const mode = open ? 'open' : 'run'
|
|
24
24
|
|
|
@@ -29,6 +29,14 @@ const endToEndTestCommand = ({
|
|
|
29
29
|
configPath,
|
|
30
30
|
...testFiles,
|
|
31
31
|
...(baseUrl ? ['--config', `baseUrl=${baseUrl}`] : []),
|
|
32
|
+
...(!open && anvilTag
|
|
33
|
+
? [
|
|
34
|
+
'--reporter',
|
|
35
|
+
cypressReporterPath,
|
|
36
|
+
'--reporter-options',
|
|
37
|
+
`anvilTag=${anvilTag}`
|
|
38
|
+
]
|
|
39
|
+
: []),
|
|
32
40
|
...convertToCLIParameters(cypressOptions)
|
|
33
41
|
])
|
|
34
42
|
}
|
|
@@ -45,8 +53,13 @@ const endToEndCommandCreator = {
|
|
|
45
53
|
name: '--open'
|
|
46
54
|
},
|
|
47
55
|
{
|
|
48
|
-
label:
|
|
56
|
+
label: "URL used as prefix for cy.visit() or cy.request() command's URL",
|
|
49
57
|
name: '--baseUrl <baseUrl>'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label:
|
|
61
|
+
"the project name matching Anvil's expected tag to generate Anvil Reports",
|
|
62
|
+
name: '--anvilTag <anvilTag>'
|
|
50
63
|
}
|
|
51
64
|
]
|
|
52
65
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const convertToCLIParametersMock = jest.fn()
|
|
2
|
+
const getPackageFilePathMock = jest.fn()
|
|
3
|
+
|
|
4
|
+
jest.mock('@toptal/davinci-cli-shared', () => ({
|
|
5
|
+
runSync: jest.fn(),
|
|
6
|
+
print: {
|
|
7
|
+
green: jest.fn()
|
|
8
|
+
},
|
|
9
|
+
convertToCLIParameters: convertToCLIParametersMock,
|
|
10
|
+
files: {
|
|
11
|
+
getPackageFilePath: getPackageFilePathMock
|
|
12
|
+
}
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
const { runSync } = require('@toptal/davinci-cli-shared')
|
|
16
|
+
|
|
17
|
+
const { action } = require('./end-to-end-tests')
|
|
18
|
+
|
|
19
|
+
describe('endToEndTestCommand', () => {
|
|
20
|
+
it('runs cypress with default options', () => {
|
|
21
|
+
convertToCLIParametersMock.mockReturnValueOnce([])
|
|
22
|
+
getPackageFilePathMock.mockReturnValueOnce('packages/qa/src/configs/cypress.config.json')
|
|
23
|
+
|
|
24
|
+
action({ options: {} })
|
|
25
|
+
|
|
26
|
+
expect(runSync).toHaveBeenCalledWith('yarn', [
|
|
27
|
+
'cypress',
|
|
28
|
+
'run',
|
|
29
|
+
'--config-file',
|
|
30
|
+
'packages/qa/src/configs/cypress.config.json'
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
expect(convertToCLIParametersMock).toHaveBeenCalledWith({})
|
|
34
|
+
expect(getPackageFilePathMock).toHaveBeenCalledWith(
|
|
35
|
+
'@toptal/davinci-qa',
|
|
36
|
+
'src/configs/cypress.config.json'
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('runs cypress with custom options', () => {
|
|
41
|
+
const spec = 'cypress/integration/activation_flow.spec.ts'
|
|
42
|
+
|
|
43
|
+
convertToCLIParametersMock.mockReturnValueOnce(['--spec', spec])
|
|
44
|
+
getPackageFilePathMock.mockReturnValueOnce('packages/qa/src/configs/cypress.config.json')
|
|
45
|
+
|
|
46
|
+
action({ options: { spec } })
|
|
47
|
+
|
|
48
|
+
expect(runSync).toHaveBeenCalledWith('yarn', [
|
|
49
|
+
'cypress',
|
|
50
|
+
'run',
|
|
51
|
+
'--config-file',
|
|
52
|
+
'packages/qa/src/configs/cypress.config.json',
|
|
53
|
+
'--spec',
|
|
54
|
+
spec
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
expect(convertToCLIParametersMock).toHaveBeenCalledWith({
|
|
58
|
+
spec
|
|
59
|
+
})
|
|
60
|
+
expect(getPackageFilePathMock).toHaveBeenCalledWith(
|
|
61
|
+
'@toptal/davinci-qa',
|
|
62
|
+
'src/configs/cypress.config.json'
|
|
63
|
+
)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const jestRunCLIMock =jest.fn().mockResolvedValue({ results: {success: true}})
|
|
2
|
+
const getPackageFilePathMock = jest.fn()
|
|
3
|
+
const getProjectRootFilePathMock = jest.fn()
|
|
4
|
+
const getProjectRootFileContentMock = jest.fn().mockReturnValue({
|
|
5
|
+
devDependencies: {}, dependencies: {},
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
jest.mock('@toptal/davinci-cli-shared', () => ({
|
|
9
|
+
runSync: jest.fn(),
|
|
10
|
+
print: {
|
|
11
|
+
green: jest.fn(),
|
|
12
|
+
grey: jest.fn(),
|
|
13
|
+
red: jest.fn(),
|
|
14
|
+
},
|
|
15
|
+
files: {
|
|
16
|
+
getPackageFilePath: getPackageFilePathMock,
|
|
17
|
+
getProjectRootFileContent: getProjectRootFileContentMock,
|
|
18
|
+
getProjectRootFilePath: getProjectRootFilePathMock
|
|
19
|
+
}
|
|
20
|
+
}))
|
|
21
|
+
|
|
22
|
+
jest.mock('jest', () => ({
|
|
23
|
+
runCLI: jestRunCLIMock
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
const { action } = require('./unit-tests')
|
|
27
|
+
const originalEnv = process.env
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
jest.clearAllMocks()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
process.env = originalEnv
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('unitTestsCommand', () => {
|
|
38
|
+
describe('when running locally', () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
delete process.env.CI
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('calls the jest CLI without additional reporters', async () => {
|
|
44
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
45
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
46
|
+
|
|
47
|
+
await action({})
|
|
48
|
+
|
|
49
|
+
expect(jestRunCLIMock).toBeCalledWith(
|
|
50
|
+
{"config": davinciJestConfigPath, "testPathPattern": []},
|
|
51
|
+
expect.anything()
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('when running on CI', () => {
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
process.env.CI = true
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('calls the jest CLI with default Davinci reporters', async () => {
|
|
63
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
64
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
65
|
+
|
|
66
|
+
await action({})
|
|
67
|
+
|
|
68
|
+
expect(jestRunCLIMock).toBeCalledWith(
|
|
69
|
+
expect.objectContaining({
|
|
70
|
+
reporters: [
|
|
71
|
+
[
|
|
72
|
+
"jest-silent-reporter",
|
|
73
|
+
{
|
|
74
|
+
useDots: true,
|
|
75
|
+
showPaths: true,
|
|
76
|
+
showWarnings: true,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
[
|
|
80
|
+
"jest-junit",
|
|
81
|
+
{
|
|
82
|
+
outputDirectory: "reports",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"jest-html-reporters",
|
|
87
|
+
{
|
|
88
|
+
publicPath: "./reports",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
expect.stringContaining("davinci/packages/qa/src/reporters/jest-anvil-reporter.js"),
|
|
93
|
+
{
|
|
94
|
+
anvilTag: undefined,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
],
|
|
98
|
+
}),
|
|
99
|
+
expect.anything()
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('allows overriding of the default Davinci reporters via custom configuration', async () => {
|
|
104
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
105
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
106
|
+
const customCLIReporter = 'My-CLI-Reporter'
|
|
107
|
+
|
|
108
|
+
await action({
|
|
109
|
+
options: {
|
|
110
|
+
anvilTag: 'MyTag',
|
|
111
|
+
reporters: customCLIReporter
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
expect(jestRunCLIMock).toBeCalledWith(
|
|
116
|
+
expect.objectContaining({
|
|
117
|
+
reporters: [customCLIReporter],
|
|
118
|
+
}),
|
|
119
|
+
expect.anything()
|
|
120
|
+
)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('allows overriding the default Davinci reporters via custom jest config', async () => {
|
|
124
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
125
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
126
|
+
const customJestConfigReporter = 'My-Jest-Config-Reporter'
|
|
127
|
+
|
|
128
|
+
getProjectRootFileContentMock.mockReturnValue({reporters: customJestConfigReporter})
|
|
129
|
+
|
|
130
|
+
await action({ options: { config: {}}})
|
|
131
|
+
|
|
132
|
+
expect(jestRunCLIMock).toBeCalledWith(
|
|
133
|
+
expect.objectContaining({
|
|
134
|
+
reporters: [customJestConfigReporter],
|
|
135
|
+
}),
|
|
136
|
+
expect.anything()
|
|
137
|
+
)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('prioritizes the CLI reporters over the custom jest config or the default Davinci reporters', async () => {
|
|
141
|
+
const davinciJestConfigPath = 'packages/qa/src/configs/jest.config.js'
|
|
142
|
+
getPackageFilePathMock.mockReturnValueOnce(davinciJestConfigPath)
|
|
143
|
+
const customCLIReporter = 'My-CLI-Reporter'
|
|
144
|
+
const customJestConfigReporter = 'My-Jest-Config-Reporter'
|
|
145
|
+
|
|
146
|
+
getProjectRootFileContentMock.mockReturnValue({ reporters: customJestConfigReporter })
|
|
147
|
+
|
|
148
|
+
await action({
|
|
149
|
+
options: {
|
|
150
|
+
anvilTag: 'MyTag',
|
|
151
|
+
reporters: customCLIReporter,
|
|
152
|
+
config: {}
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
expect(jestRunCLIMock).toBeCalledWith(
|
|
157
|
+
expect.objectContaining({
|
|
158
|
+
reporters: [customCLIReporter],
|
|
159
|
+
}),
|
|
160
|
+
expect.anything()
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
2
|
+
const fs = require('fs-extra')
|
|
3
|
+
|
|
4
|
+
const anvilMapper = ({
|
|
5
|
+
fileName,
|
|
6
|
+
lineNumber,
|
|
7
|
+
status,
|
|
8
|
+
durationInSeconds,
|
|
9
|
+
scenarioName,
|
|
10
|
+
description,
|
|
11
|
+
error,
|
|
12
|
+
backtrace,
|
|
13
|
+
testType,
|
|
14
|
+
pendingMessage,
|
|
15
|
+
tag
|
|
16
|
+
}) => ({
|
|
17
|
+
file_name: fileName,
|
|
18
|
+
line_number: lineNumber,
|
|
19
|
+
status: status === 'todo' ? 'pending' : status,
|
|
20
|
+
duration: durationInSeconds,
|
|
21
|
+
scenario_name: scenarioName,
|
|
22
|
+
description,
|
|
23
|
+
error,
|
|
24
|
+
backtrace,
|
|
25
|
+
test_type: testType,
|
|
26
|
+
pending_message: pendingMessage,
|
|
27
|
+
tag
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const generateAnvilResults = (fileName, testResults) => {
|
|
31
|
+
const reportPath = './reports'
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
fs.ensureDirSync(reportPath)
|
|
35
|
+
fs.writeJsonSync(`${reportPath}/${fileName}`, testResults)
|
|
36
|
+
print.green('[anvil-reporter] Anvil reports generated successfully!')
|
|
37
|
+
} catch (err) {
|
|
38
|
+
print.red('[anvil-reporter] Failed to create Anvil test results!', err)
|
|
39
|
+
throw err
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
anvilMapper,
|
|
45
|
+
generateAnvilResults
|
|
46
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const fs = require('fs-extra')
|
|
2
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
3
|
+
|
|
4
|
+
const { anvilMapper, generateAnvilResults } = require('./anvil-results-helper')
|
|
5
|
+
|
|
6
|
+
describe('Anvil results helper', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.resetModules()
|
|
9
|
+
jest.resetAllMocks()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe('anvilMapper', () => {
|
|
13
|
+
it('outputs an Anvil-compatible object', () => {
|
|
14
|
+
const mappedValue = anvilMapper({
|
|
15
|
+
fileName:
|
|
16
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
17
|
+
backtrace: null,
|
|
18
|
+
description: '1 + 1 returns 2',
|
|
19
|
+
durationInSeconds: 0.003,
|
|
20
|
+
error: null,
|
|
21
|
+
lineNumber: 2,
|
|
22
|
+
pendingMessage: null,
|
|
23
|
+
scenarioName: 'Example test suite/1 + 1 returns 2',
|
|
24
|
+
status: 'passed',
|
|
25
|
+
tag: 'platform',
|
|
26
|
+
testType: 'unit'
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
expect(mappedValue).toEqual({
|
|
30
|
+
file_name:
|
|
31
|
+
'/davinci/packages/qa/src/reporters/jest-anvil-reporter-mocker.test.js',
|
|
32
|
+
line_number: 2,
|
|
33
|
+
status: 'passed',
|
|
34
|
+
duration: 0.003,
|
|
35
|
+
scenario_name: 'Example test suite/1 + 1 returns 2',
|
|
36
|
+
description: '1 + 1 returns 2',
|
|
37
|
+
error: null,
|
|
38
|
+
backtrace: null,
|
|
39
|
+
test_type: 'unit',
|
|
40
|
+
pending_message: null,
|
|
41
|
+
tag: 'platform'
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('converts "todo" status to pending', () => {
|
|
46
|
+
const mappedValue = anvilMapper({ status: 'todo' })
|
|
47
|
+
|
|
48
|
+
expect(mappedValue.status).toBe('pending')
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('generateAnvilResults', () => {
|
|
53
|
+
it('creates a report with the data passed in', () => {
|
|
54
|
+
const writeJsonMock = jest.spyOn(fs, 'writeJsonSync')
|
|
55
|
+
const printMock = jest.spyOn(print, 'green')
|
|
56
|
+
|
|
57
|
+
generateAnvilResults('anvil_cypress_test_results.json', { test: 123 })
|
|
58
|
+
|
|
59
|
+
expect(writeJsonMock).toHaveBeenCalledWith(
|
|
60
|
+
'./reports/anvil_cypress_test_results.json',
|
|
61
|
+
{ test: 123 }
|
|
62
|
+
)
|
|
63
|
+
expect(printMock).toHaveBeenCalledWith(
|
|
64
|
+
'[anvil-reporter] Anvil reports generated successfully!'
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('throws an error when unable to create report', () => {
|
|
69
|
+
const mockError = new Error('My error!')
|
|
70
|
+
|
|
71
|
+
jest.spyOn(fs, 'ensureDirSync').mockImplementation(() => {
|
|
72
|
+
throw mockError
|
|
73
|
+
})
|
|
74
|
+
const printMock = jest.spyOn(print, 'red')
|
|
75
|
+
|
|
76
|
+
expect(() =>
|
|
77
|
+
generateAnvilResults('anvil_cypress_test_results.json', { test: 123 })
|
|
78
|
+
).toThrow()
|
|
79
|
+
|
|
80
|
+
expect(printMock).toHaveBeenCalledTimes(1)
|
|
81
|
+
expect(printMock).toHaveBeenCalledWith(
|
|
82
|
+
'[anvil-reporter] Failed to create Anvil test results!',
|
|
83
|
+
mockError
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const { print } = require('@toptal/davinci-cli-shared')
|
|
2
|
+
const { Runner, reporters } = require('mocha')
|
|
3
|
+
|
|
4
|
+
const { anvilMapper, generateAnvilResults } = require('./anvil-results-helper')
|
|
5
|
+
|
|
6
|
+
const { Spec, Base } = reporters
|
|
7
|
+
const {
|
|
8
|
+
EVENT_RUN_END,
|
|
9
|
+
EVENT_TEST_FAIL,
|
|
10
|
+
EVENT_TEST_PASS,
|
|
11
|
+
EVENT_TEST_PENDING,
|
|
12
|
+
EVENT_TEST_RETRY
|
|
13
|
+
} = Runner.constants
|
|
14
|
+
|
|
15
|
+
class CypressAnvilReporter extends Base {
|
|
16
|
+
constructor(runner, options) {
|
|
17
|
+
super(runner, options)
|
|
18
|
+
const tests = []
|
|
19
|
+
const joinParentTitles = obj =>
|
|
20
|
+
obj?.parent?.title
|
|
21
|
+
? `${joinParentTitles(obj.parent)}/${obj.title}`
|
|
22
|
+
: obj.title
|
|
23
|
+
|
|
24
|
+
// Spec is Cypress's default reporter, but it misses retries
|
|
25
|
+
this._specReporter = new Spec(
|
|
26
|
+
runner.on(EVENT_TEST_RETRY, test => {
|
|
27
|
+
print.yellow(
|
|
28
|
+
`(Attempt ${test?.currentRetry + 1} of ${test?.retries}) ${
|
|
29
|
+
test?.title
|
|
30
|
+
}`
|
|
31
|
+
)
|
|
32
|
+
}),
|
|
33
|
+
options
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const anvilTag = options?.reporterOptions?.anvilTag
|
|
37
|
+
|
|
38
|
+
if (!anvilTag) {
|
|
39
|
+
print.yellow(
|
|
40
|
+
"[anvil-reporter] --anvilTag option is missing! anvil_cypress_test_results.json won't be generated."
|
|
41
|
+
)
|
|
42
|
+
} else {
|
|
43
|
+
runner
|
|
44
|
+
.on(EVENT_TEST_PASS, test => {
|
|
45
|
+
tests.push(
|
|
46
|
+
anvilMapper({
|
|
47
|
+
fileName: test?.invocationDetails?.absoluteFile,
|
|
48
|
+
lineNumber: test?.invocationDetails?.line,
|
|
49
|
+
status: test?.state,
|
|
50
|
+
durationInSeconds: test?.duration / 1000,
|
|
51
|
+
scenarioName: joinParentTitles(test),
|
|
52
|
+
description: test?.title,
|
|
53
|
+
error: test?.err?.message || null,
|
|
54
|
+
backtrace: test?.err?.stack || null,
|
|
55
|
+
testType: 'integration',
|
|
56
|
+
pendingMessage: null,
|
|
57
|
+
tag: anvilTag
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
.on(EVENT_TEST_FAIL, test => {
|
|
62
|
+
tests.push(
|
|
63
|
+
anvilMapper({
|
|
64
|
+
fileName: test?.invocationDetails?.absoluteFile,
|
|
65
|
+
lineNumber: test?.invocationDetails?.line,
|
|
66
|
+
status: test?.state,
|
|
67
|
+
durationInSeconds: test?.duration / 1000,
|
|
68
|
+
scenarioName: joinParentTitles(test),
|
|
69
|
+
description: test?.title,
|
|
70
|
+
error: test?.err?.message || null,
|
|
71
|
+
backtrace: test?.err?.stack || null,
|
|
72
|
+
testType: 'integration',
|
|
73
|
+
pendingMessage: null,
|
|
74
|
+
tag: anvilTag
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
})
|
|
78
|
+
.on(EVENT_TEST_PENDING, test => {
|
|
79
|
+
tests.push(
|
|
80
|
+
anvilMapper({
|
|
81
|
+
fileName: test?.invocationDetails?.absoluteFile,
|
|
82
|
+
lineNumber: test?.invocationDetails?.line,
|
|
83
|
+
status: test?.state,
|
|
84
|
+
durationInSeconds: 0,
|
|
85
|
+
scenarioName: joinParentTitles(test),
|
|
86
|
+
description: test?.title,
|
|
87
|
+
error: test?.err?.message || null,
|
|
88
|
+
backtrace: test?.err?.stack || null,
|
|
89
|
+
testType: 'integration',
|
|
90
|
+
pendingMessage: null,
|
|
91
|
+
tag: anvilTag
|
|
92
|
+
})
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
.on(EVENT_TEST_RETRY, test => {
|
|
96
|
+
tests.push(
|
|
97
|
+
anvilMapper({
|
|
98
|
+
fileName: test?.invocationDetails?.absoluteFile,
|
|
99
|
+
lineNumber: test?.invocationDetails?.line,
|
|
100
|
+
status: 'retried',
|
|
101
|
+
durationInSeconds: test?.duration / 1000,
|
|
102
|
+
scenarioName: joinParentTitles(test),
|
|
103
|
+
description: test?.title,
|
|
104
|
+
error: test?.err?.message || null,
|
|
105
|
+
backtrace: test?.err?.stack || null,
|
|
106
|
+
testType: 'integration',
|
|
107
|
+
pendingMessage: null,
|
|
108
|
+
tag: anvilTag
|
|
109
|
+
})
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
.once(EVENT_RUN_END, () => {
|
|
113
|
+
generateAnvilResults('anvil_cypress_test_results.json', {
|
|
114
|
+
test_results: tests
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = CypressAnvilReporter
|