@docupace/pipeline 1.0.39-matttest.42 → 1.0.39-matttest.44
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/jest.config.js +14 -0
- package/package.json +6 -1
- package/src/next/config.js +19 -1
- package/src/next/deploy.js +11 -2
- package/tests/README.md +164 -0
- package/tests/WORKING_TEST_GUIDE.md +222 -0
- package/tests/next/alias.test.js +99 -0
- package/tests/next/apache.test.js +110 -0
- package/tests/next/config-simple.test.js +53 -0
- package/tests/next/config.test.js +164 -0
- package/tests/next/connect.test.js +187 -0
- package/tests/next/copy.test.js +123 -0
- package/tests/next/deploy.test.js +294 -0
- package/tests/next/haproxy.test.js +128 -0
- package/tests/next/jenkins-simple.test.js +195 -0
- package/tests/next/jenkins-working.test.js +250 -0
- package/tests/next/jenkins.test.js +75 -0
- package/tests/next/jira.test.js +51 -0
- package/tests/next/logger.test.js +4 -0
- package/tests/next/pipline.test.js +28 -0
- package/tests/next/publish.test.js +33 -0
- package/tests/next/pull-simple.test.js +74 -0
- package/tests/next/pull.test.js +136 -0
- package/tests/next/sonar.test.js +232 -0
- package/tests/next/util.test.js +2 -0
- package/tests/next/vault.test.js +192 -0
- package/tests/setup.js +8 -0
- package/tests/simple.test.js +17 -0
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docupace/pipeline",
|
|
3
|
-
"version": "1.0.39-matttest.
|
|
3
|
+
"version": "1.0.39-matttest.44",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,14 +33,19 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@eslint/js": "^9.17.0",
|
|
36
|
+
"@jest/globals": "^30.0.0-beta.3",
|
|
36
37
|
"esbuild": "^0.24.0",
|
|
37
38
|
"eslint": "^9.17.0",
|
|
38
39
|
"eslint-config-prettier": "^9.1.0",
|
|
39
40
|
"eslint-plugin-prettier": "^5.2.1",
|
|
40
41
|
"globals": "^15.14.0",
|
|
42
|
+
"jest": "^29.7.0",
|
|
41
43
|
"prettier": "^3.4.2"
|
|
42
44
|
},
|
|
43
45
|
"scripts": {
|
|
46
|
+
"test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest",
|
|
47
|
+
"test:watch": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --watch",
|
|
48
|
+
"test:coverage": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --coverage",
|
|
44
49
|
"test-deploy-core": "dp-next-cli deploy-core-pipeline dev template",
|
|
45
50
|
"test-deploy-from-site": "dp-next-cli deploy-from-site --from-env dev --to-env dev --from-site financialdev --to-site template --deploy-core true",
|
|
46
51
|
"test-run-pipline": "dp-next-cli run-pipeline -r docupace-next-e2e -b master -p run-tests-qa",
|
package/src/next/config.js
CHANGED
|
@@ -35,17 +35,35 @@ export const environmentConfig = {
|
|
|
35
35
|
export const appInfo = {
|
|
36
36
|
'graphql-server': {
|
|
37
37
|
repositoryName: 'docupace-graphql-server',
|
|
38
|
-
imageName: 'docupace-graphql-
|
|
38
|
+
imageName: 'docupace-graphql-server',
|
|
39
39
|
deployAttributes: [
|
|
40
40
|
'image.tag',
|
|
41
41
|
'graphqlServer.siteConfigRemoteBranch',
|
|
42
42
|
'graphqlServer.standardConfigRemoteBranch',
|
|
43
43
|
],
|
|
44
44
|
},
|
|
45
|
+
cc: {
|
|
46
|
+
repositoryName: 'docupace-ui-main',
|
|
47
|
+
imageName: 'cc-ui-app',
|
|
48
|
+
deployAttributes: ['image.tag'],
|
|
49
|
+
getAppRevision: (config) => {
|
|
50
|
+
const version = config.image.tag.slice(1);
|
|
51
|
+
return 'cc-ui-app@' + version;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
45
54
|
ui: {
|
|
46
55
|
repositoryName: 'docupace-ui-main',
|
|
47
56
|
imageName: 'enterprise-ui-app',
|
|
48
57
|
deployAttributes: ['image.tag'],
|
|
58
|
+
getAppRevision: (config) => {
|
|
59
|
+
const tag = config.image.tag;
|
|
60
|
+
const version = tag.startsWith('v') ? tag.slice(1) : tag;
|
|
61
|
+
if (semver.gt(version, UI_MONO_VERSION)) {
|
|
62
|
+
return 'enterprise-ui-app@' + version;
|
|
63
|
+
} else {
|
|
64
|
+
return tag;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
49
67
|
updateConfigFunction: (config) => {
|
|
50
68
|
if (config.image.repository.endsWith('/docupace-ui-main')) {
|
|
51
69
|
const tag = config.image.tag;
|
package/src/next/deploy.js
CHANGED
|
@@ -303,7 +303,13 @@ export async function deployAppWithTag(application, env, site, deployTag) {
|
|
|
303
303
|
|
|
304
304
|
if (env !== 'dev') {
|
|
305
305
|
const appDetails = appInfo[application];
|
|
306
|
-
await copy2(
|
|
306
|
+
await copy2(
|
|
307
|
+
appDetails.repositoryName,
|
|
308
|
+
'dev',
|
|
309
|
+
env,
|
|
310
|
+
deployTag,
|
|
311
|
+
appDetails.imageName,
|
|
312
|
+
);
|
|
307
313
|
}
|
|
308
314
|
|
|
309
315
|
const { repoPath, deployConfigFilePath, deployConfig } =
|
|
@@ -390,6 +396,7 @@ export async function deployApp(
|
|
|
390
396
|
fromEnv,
|
|
391
397
|
toEnv,
|
|
392
398
|
fromDeployConfig.image.tag,
|
|
399
|
+
appDetails.imageName,
|
|
393
400
|
);
|
|
394
401
|
}
|
|
395
402
|
|
|
@@ -419,7 +426,9 @@ export async function deployApp(
|
|
|
419
426
|
deployConfigFilePath: toDeployAppConfigFilePath,
|
|
420
427
|
} = await readDeployConfig(application, toEnv, toSite, 'app');
|
|
421
428
|
|
|
422
|
-
toDeployAppConfig.revision =
|
|
429
|
+
toDeployAppConfig.revision = appDetails.getAppRevision
|
|
430
|
+
? appDetails.getAppRevision(fromDeployConfig)
|
|
431
|
+
: fromDeployConfig.image.tag;
|
|
423
432
|
|
|
424
433
|
// Write updated configuration to the target YAML file
|
|
425
434
|
writeDeployConfig(toDeployConfigFilePath, toDeployConfig);
|
package/tests/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Unit Tests for Pipeline Shared Scripts
|
|
2
|
+
|
|
3
|
+
This directory contains comprehensive unit tests for all modules in the `src/next` directory.
|
|
4
|
+
|
|
5
|
+
## Test Structure
|
|
6
|
+
|
|
7
|
+
The test suite covers the following modules:
|
|
8
|
+
|
|
9
|
+
### Core Modules
|
|
10
|
+
- **alias.js** - Tests for Auth0 alias creation functionality
|
|
11
|
+
- **apache.js** - Tests for Apache site configuration
|
|
12
|
+
- **config.js** - Tests for environment and application configuration
|
|
13
|
+
- **connect.js** - Tests for Connect site cloning and configuration
|
|
14
|
+
- **copy.js** - Tests for Docker image copying between registries
|
|
15
|
+
- **deploy.js** - Tests for deployment functionality (GitOps, YAML config management)
|
|
16
|
+
- **haproxy.js** - Tests for HAProxy configuration synchronization
|
|
17
|
+
- **jenkins.js** - Tests for Jenkins job triggering and monitoring
|
|
18
|
+
- **jira.js** - Tests for Jira API integration
|
|
19
|
+
- **logger.js** - Tests for command logging wrapper
|
|
20
|
+
- **pipline.js** - Tests for Bitbucket pipeline triggering
|
|
21
|
+
- **publish.js** - Tests for Docker image publishing
|
|
22
|
+
- **pull.js** - Tests for Docker image pulling
|
|
23
|
+
- **sonar.js** - Tests for SonarQube analysis
|
|
24
|
+
- **util.js** - Tests for utility functions (monorepo, git operations)
|
|
25
|
+
- **vault.js** - Tests for HashiCorp Vault integration
|
|
26
|
+
|
|
27
|
+
## Running Tests
|
|
28
|
+
|
|
29
|
+
### Run All Tests
|
|
30
|
+
```bash
|
|
31
|
+
npm test
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Run Tests with Coverage
|
|
35
|
+
```bash
|
|
36
|
+
npm run test:coverage
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Run Tests in Watch Mode
|
|
40
|
+
```bash
|
|
41
|
+
npm run test:watch
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Run Specific Test File
|
|
45
|
+
```bash
|
|
46
|
+
npm test tests/next/config.test.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Run Tests Matching Pattern
|
|
50
|
+
```bash
|
|
51
|
+
npm test -- --testNamePattern="should create alias"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Test Features
|
|
55
|
+
|
|
56
|
+
### Mocking Strategy
|
|
57
|
+
- **External Dependencies**: All external libraries (axios, zx, fs-extra) are mocked
|
|
58
|
+
- **Environment Variables**: Tests use isolated environment variable mocking
|
|
59
|
+
- **File System**: File system operations are mocked to avoid actual file I/O
|
|
60
|
+
- **Shell Commands**: All shell commands via zx are mocked for isolation
|
|
61
|
+
|
|
62
|
+
### Test Coverage
|
|
63
|
+
Each test file covers:
|
|
64
|
+
- **Happy Path Scenarios**: Normal operation with valid inputs
|
|
65
|
+
- **Error Handling**: Error cases and edge conditions
|
|
66
|
+
- **Environment Variable Validation**: Missing or invalid environment variables
|
|
67
|
+
- **API Error Handling**: Network failures and API errors
|
|
68
|
+
- **Input Validation**: Invalid or missing function parameters
|
|
69
|
+
|
|
70
|
+
### Example Test Structure
|
|
71
|
+
```javascript
|
|
72
|
+
import { jest } from '@jest/globals';
|
|
73
|
+
import { functionToTest } from '../../src/next/module.js';
|
|
74
|
+
|
|
75
|
+
// Mock external dependencies
|
|
76
|
+
const mockDependency = jest.fn();
|
|
77
|
+
jest.unstable_mockModule('external-library', () => ({
|
|
78
|
+
default: mockDependency,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
describe('module.js', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
jest.clearAllMocks();
|
|
84
|
+
// Reset environment variables
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('functionToTest', () => {
|
|
88
|
+
it('should perform expected operation', async () => {
|
|
89
|
+
// Arrange - set up mocks and test data
|
|
90
|
+
// Act - call the function
|
|
91
|
+
// Assert - verify results and mock calls
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should handle error cases', async () => {
|
|
95
|
+
// Test error scenarios
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Test Configuration
|
|
102
|
+
|
|
103
|
+
The test suite uses Jest with the following configuration:
|
|
104
|
+
- **Test Environment**: Node.js
|
|
105
|
+
- **Test Pattern**: `**/tests/**/*.test.js`
|
|
106
|
+
- **Coverage**: Collects coverage from `src/**/*.js` (excluding CLI files)
|
|
107
|
+
- **Module Type**: ES Modules
|
|
108
|
+
|
|
109
|
+
## Common Test Patterns
|
|
110
|
+
|
|
111
|
+
### Testing Async Functions
|
|
112
|
+
```javascript
|
|
113
|
+
it('should handle async operations', async () => {
|
|
114
|
+
mockFunction.mockResolvedValue(expectedResult);
|
|
115
|
+
const result = await functionUnderTest();
|
|
116
|
+
expect(result).toEqual(expectedResult);
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Testing Error Handling
|
|
121
|
+
```javascript
|
|
122
|
+
it('should handle errors gracefully', async () => {
|
|
123
|
+
mockFunction.mockRejectedValue(new Error('Test error'));
|
|
124
|
+
await expect(functionUnderTest()).rejects.toThrow('Test error');
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Testing Environment Variables
|
|
129
|
+
```javascript
|
|
130
|
+
it('should use environment variables', () => {
|
|
131
|
+
process.env.TEST_VAR = 'test-value';
|
|
132
|
+
const result = functionUnderTest();
|
|
133
|
+
expect(result).toContain('test-value');
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Testing Shell Commands
|
|
138
|
+
```javascript
|
|
139
|
+
it('should execute correct shell commands', async () => {
|
|
140
|
+
mock$.mockResolvedValue({ stdout: 'success' });
|
|
141
|
+
await functionUnderTest();
|
|
142
|
+
expect(mock$).toHaveBeenCalledWith(
|
|
143
|
+
expect.arrayContaining([expect.stringContaining('expected-command')])
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Adding New Tests
|
|
149
|
+
|
|
150
|
+
When adding new tests:
|
|
151
|
+
|
|
152
|
+
1. Create a new test file following the naming convention: `module-name.test.js`
|
|
153
|
+
2. Import required testing utilities from `@jest/globals`
|
|
154
|
+
3. Mock external dependencies using `jest.unstable_mockModule`
|
|
155
|
+
4. Follow the AAA pattern (Arrange, Act, Assert)
|
|
156
|
+
5. Test both success and failure scenarios
|
|
157
|
+
6. Mock all external dependencies to ensure test isolation
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- Tests are designed to run in isolation without external dependencies
|
|
162
|
+
- All file system operations, network calls, and shell commands are mocked
|
|
163
|
+
- Environment variables are reset between tests to prevent cross-test pollution
|
|
164
|
+
- The test suite focuses on unit testing individual functions rather than integration testing
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Working Test Guide for ES Modules
|
|
2
|
+
|
|
3
|
+
This guide explains how to write working unit tests for the ES modules in this project.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
The original comprehensive test files had issues with ES module imports and Jest configuration. The main issues were:
|
|
8
|
+
|
|
9
|
+
1. ES module import syntax not working properly with Jest
|
|
10
|
+
2. Mock configuration problems with `jest.unstable_mockModule`
|
|
11
|
+
3. Template literal expectations not matching actual zx calls
|
|
12
|
+
|
|
13
|
+
## Solution
|
|
14
|
+
|
|
15
|
+
Use the working pattern demonstrated in the example files:
|
|
16
|
+
- `tests/simple.test.js` - Basic Jest functionality
|
|
17
|
+
- `tests/next/config-simple.test.js` - Testing modules without mocking
|
|
18
|
+
- `tests/next/pull-simple.test.js` - Testing modules with mocking
|
|
19
|
+
|
|
20
|
+
## Working Test Pattern
|
|
21
|
+
|
|
22
|
+
### 1. Basic Test Structure
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
// Import Jest utilities
|
|
26
|
+
import { jest } from '@jest/globals';
|
|
27
|
+
|
|
28
|
+
// For modules that need mocking, mock BEFORE importing
|
|
29
|
+
const mockFunction = jest.fn();
|
|
30
|
+
jest.unstable_mockModule('external-module', () => ({
|
|
31
|
+
functionName: mockFunction,
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
// Import the module under test AFTER mocking dependencies
|
|
35
|
+
const { functionToTest } = await import('../../src/next/module.js');
|
|
36
|
+
|
|
37
|
+
describe('module.js', () => {
|
|
38
|
+
// Test implementation
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Testing Modules Without External Dependencies
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
import { jest } from '@jest/globals';
|
|
46
|
+
|
|
47
|
+
// Import module directly
|
|
48
|
+
let configModule;
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
configModule = await import('../../src/next/config.js');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('config.js', () => {
|
|
54
|
+
it('should have correct configuration', () => {
|
|
55
|
+
expect(configModule.environments).toEqual(['dev', 'qa', 'uat', 'stage', 'prod']);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3. Testing Modules With External Dependencies
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import { jest } from '@jest/globals';
|
|
64
|
+
|
|
65
|
+
// Mock dependencies BEFORE importing
|
|
66
|
+
const mock$ = jest.fn();
|
|
67
|
+
jest.unstable_mockModule('zx', () => ({
|
|
68
|
+
$: mock$,
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
// Import after mocking
|
|
72
|
+
const { functionToTest } = await import('../../src/next/module.js');
|
|
73
|
+
|
|
74
|
+
describe('module.js', () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
jest.clearAllMocks();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should call external dependency correctly', async () => {
|
|
80
|
+
mock$.mockResolvedValue({ stdout: 'success' });
|
|
81
|
+
|
|
82
|
+
await functionToTest('arg1', 'arg2');
|
|
83
|
+
|
|
84
|
+
// For zx template literals, match the exact structure
|
|
85
|
+
expect(mock$).toHaveBeenCalledWith(
|
|
86
|
+
['command ', ' ', ''], // Template literal parts
|
|
87
|
+
'arg1', // First interpolated value
|
|
88
|
+
'arg2' // Second interpolated value
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. Understanding zx Template Literal Calls
|
|
95
|
+
|
|
96
|
+
When zx processes a template literal like:
|
|
97
|
+
```javascript
|
|
98
|
+
await $`docker pull ${registry}/${image}`;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The mock receives:
|
|
102
|
+
- First argument: Array of string parts: `['docker pull ', '/', '']`
|
|
103
|
+
- Subsequent arguments: The interpolated values: `registry`, `image`
|
|
104
|
+
|
|
105
|
+
So your test expectation should be:
|
|
106
|
+
```javascript
|
|
107
|
+
expect(mock$).toHaveBeenCalledWith(
|
|
108
|
+
['docker pull ', '/', ''],
|
|
109
|
+
'registry-value',
|
|
110
|
+
'image-value'
|
|
111
|
+
);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 5. Environment Variable Testing
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
describe('function with env vars', () => {
|
|
118
|
+
const originalEnv = process.env;
|
|
119
|
+
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
process.env = { ...originalEnv };
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
afterEach(() => {
|
|
125
|
+
process.env = originalEnv;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should use environment variables', () => {
|
|
129
|
+
process.env.TEST_VAR = 'test-value';
|
|
130
|
+
// Test implementation
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Running Tests
|
|
136
|
+
|
|
137
|
+
### Prerequisites
|
|
138
|
+
Make sure you have the correct configuration:
|
|
139
|
+
|
|
140
|
+
**jest.config.js:**
|
|
141
|
+
```javascript
|
|
142
|
+
export default {
|
|
143
|
+
testEnvironment: 'node',
|
|
144
|
+
testMatch: [
|
|
145
|
+
'**/tests/**/*.test.js'
|
|
146
|
+
],
|
|
147
|
+
collectCoverageFrom: [
|
|
148
|
+
'src/**/*.js',
|
|
149
|
+
'!src/**/cli.js'
|
|
150
|
+
],
|
|
151
|
+
transform: {},
|
|
152
|
+
moduleNameMapper: {
|
|
153
|
+
'^(\\.{1,2}/.*)\\.js$': '$1'
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**package.json scripts:**
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"scripts": {
|
|
162
|
+
"test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest",
|
|
163
|
+
"test:watch": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --watch",
|
|
164
|
+
"test:coverage": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --coverage"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Commands
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Run all tests
|
|
173
|
+
npm test
|
|
174
|
+
|
|
175
|
+
# Run specific test file
|
|
176
|
+
npm test tests/next/config-simple.test.js
|
|
177
|
+
|
|
178
|
+
# Run with coverage
|
|
179
|
+
npm run test:coverage
|
|
180
|
+
|
|
181
|
+
# Run in watch mode
|
|
182
|
+
npm run test:watch
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Creating New Tests
|
|
186
|
+
|
|
187
|
+
1. **Create test file**: `tests/next/your-module.test.js`
|
|
188
|
+
2. **Follow the pattern**: Use the working examples as templates
|
|
189
|
+
3. **Mock dependencies**: Mock external modules before importing your module
|
|
190
|
+
4. **Test thoroughly**: Include happy path, error cases, and edge conditions
|
|
191
|
+
5. **Verify expectations**: Make sure zx template literal expectations match the actual call structure
|
|
192
|
+
|
|
193
|
+
## Example Test Files
|
|
194
|
+
|
|
195
|
+
- `tests/simple.test.js` - Basic Jest functionality test
|
|
196
|
+
- `tests/next/config-simple.test.js` - Configuration testing without mocks
|
|
197
|
+
- `tests/next/pull-simple.test.js` - Full example with mocking and zx calls
|
|
198
|
+
|
|
199
|
+
## Common Issues and Solutions
|
|
200
|
+
|
|
201
|
+
### Issue: `Cannot use import statement outside a module`
|
|
202
|
+
**Solution**: Make sure you're using `NODE_OPTIONS="--experimental-vm-modules"` and the module is imported correctly.
|
|
203
|
+
|
|
204
|
+
### Issue: Mock expectations don't match
|
|
205
|
+
**Solution**: Log the actual mock calls to see the exact structure:
|
|
206
|
+
```javascript
|
|
207
|
+
console.log('Mock calls:', mock$.mock.calls);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Issue: Environment variables not working
|
|
211
|
+
**Solution**: Make sure to properly reset environment variables in `beforeEach`/`afterEach`.
|
|
212
|
+
|
|
213
|
+
## Writing Comprehensive Tests
|
|
214
|
+
|
|
215
|
+
For each module, test:
|
|
216
|
+
1. **Happy path**: Normal operation with valid inputs
|
|
217
|
+
2. **Error handling**: What happens when external calls fail
|
|
218
|
+
3. **Input validation**: Invalid or missing parameters
|
|
219
|
+
4. **Environment variables**: Missing or invalid env vars
|
|
220
|
+
5. **Edge cases**: Boundary conditions and unusual inputs
|
|
221
|
+
|
|
222
|
+
This working pattern provides a solid foundation for testing all the ES modules in the project while avoiding the common pitfalls with Jest and ES module configuration.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { createAlias } from '../../src/next/alias.js';
|
|
3
|
+
|
|
4
|
+
// Mock the @docupace/core-client module
|
|
5
|
+
const mockDomainApi = {
|
|
6
|
+
listRecords: jest.fn(),
|
|
7
|
+
create: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const mockBasicAuth = jest.fn();
|
|
11
|
+
|
|
12
|
+
jest.unstable_mockModule('@docupace/core-client', () => ({
|
|
13
|
+
BasicAuth: mockBasicAuth,
|
|
14
|
+
DomainApi: jest.fn(() => mockDomainApi),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('alias.js', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('createAlias', () => {
|
|
23
|
+
it('should create an alias successfully', async () => {
|
|
24
|
+
const mockUserRecord = { id: 'user123' };
|
|
25
|
+
mockDomainApi.listRecords.mockResolvedValue({
|
|
26
|
+
records: [mockUserRecord],
|
|
27
|
+
});
|
|
28
|
+
mockDomainApi.create.mockResolvedValue();
|
|
29
|
+
|
|
30
|
+
await createAlias(
|
|
31
|
+
'https://www.dev.docupaceinc.com/financialdev',
|
|
32
|
+
'testuser',
|
|
33
|
+
'password',
|
|
34
|
+
'Connect',
|
|
35
|
+
'testalias@clients'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(mockBasicAuth).toHaveBeenCalledWith('testuser', 'password');
|
|
39
|
+
expect(mockDomainApi.listRecords).toHaveBeenCalledWith(50, {
|
|
40
|
+
filter: expect.stringContaining('testuser'),
|
|
41
|
+
});
|
|
42
|
+
expect(mockDomainApi.create).toHaveBeenCalledWith({
|
|
43
|
+
domainId: 302,
|
|
44
|
+
'5001': 'user123',
|
|
45
|
+
'9102': 'Connect',
|
|
46
|
+
'9504': 'testalias@clients',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle API errors gracefully', async () => {
|
|
51
|
+
mockDomainApi.listRecords.mockRejectedValue(new Error('API Error'));
|
|
52
|
+
|
|
53
|
+
await expect(
|
|
54
|
+
createAlias(
|
|
55
|
+
'https://www.dev.docupaceinc.com/financialdev',
|
|
56
|
+
'testuser',
|
|
57
|
+
'password',
|
|
58
|
+
'Connect',
|
|
59
|
+
'testalias@clients'
|
|
60
|
+
)
|
|
61
|
+
).rejects.toThrow('API Error');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should create correct user filter', async () => {
|
|
65
|
+
const mockUserRecord = { id: 'user123' };
|
|
66
|
+
mockDomainApi.listRecords.mockResolvedValue({
|
|
67
|
+
records: [mockUserRecord],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await createAlias(
|
|
71
|
+
'https://www.dev.docupaceinc.com/financialdev',
|
|
72
|
+
'testuser',
|
|
73
|
+
'password',
|
|
74
|
+
'Connect',
|
|
75
|
+
'testalias@clients'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const filterCall = mockDomainApi.listRecords.mock.calls[0][1];
|
|
79
|
+
const parsedFilter = JSON.parse(filterCall.filter);
|
|
80
|
+
|
|
81
|
+
expect(parsedFilter).toEqual({
|
|
82
|
+
orSections: [
|
|
83
|
+
{
|
|
84
|
+
andSections: [
|
|
85
|
+
{
|
|
86
|
+
attrId: 9501,
|
|
87
|
+
'@type': 'string',
|
|
88
|
+
not: false,
|
|
89
|
+
orSections: [
|
|
90
|
+
{ searchType: 'EXACT_MATCH', matchToValues: ['testuser'] },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|