Skip to content

Commit b0fb6d8

Browse files
authored
Merge pull request #54 from eviltester/34-feature-add-data-driven-for-unit-tests
34 feature add data driven for unit tests
2 parents 0442831 + 5c8e04a commit b0fb6d8

75 files changed

Lines changed: 4588 additions & 204 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/node.js.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,53 @@ jobs:
2424
node-version: ${{ matrix.node-version }}
2525
cache: 'npm'
2626

27+
- name: Set up Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: '3.12'
31+
32+
- name: Set up Ruby
33+
uses: ruby/setup-ruby@v1
34+
with:
35+
ruby-version: '3.3'
36+
37+
- name: Set up PHP
38+
uses: shivammathur/setup-php@v2
39+
with:
40+
php-version: '8.3'
41+
42+
- name: Set up Java
43+
uses: actions/setup-java@v4
44+
with:
45+
distribution: temurin
46+
java-version: '21'
47+
48+
- name: Set up .NET
49+
uses: actions/setup-dotnet@v4
50+
with:
51+
dotnet-version: '8.0.x'
52+
53+
- name: Install Perl and Kotlin compiler
54+
run: |
55+
sudo apt-get update
56+
sudo apt-get install -y perl unzip
57+
KOTLIN_VERSION=2.1.21
58+
wget -q "https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip"
59+
unzip -q "kotlin-compiler-${KOTLIN_VERSION}.zip"
60+
sudo mv kotlinc /opt/kotlinc
61+
echo "/opt/kotlinc/bin" >> "$GITHUB_PATH"
62+
63+
- name: Verify language toolchains
64+
run: |
65+
node --version
66+
python --version
67+
ruby --version
68+
php --version
69+
perl --version
70+
javac -version
71+
dotnet --version
72+
kotlinc -version
73+
2774
- name: Install dependencies
2875
run: npm ci
2976

app.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
v20220801.001 Built by <a href="https://eviltester.com" target="_blank">Alan Richardson</a>
8484
</p>
8585
<p>Using
86-
<a href="https://ag-grid.com" target="_blank">AG Grid</a> Community Edition,
86+
<a href="https://tabulator.info" target="_blank">Tabulator</a> Data Grid,
8787
<a href="http://fent.github.io/randexp.js/" target="_blank">RandExp.js</a>,
8888
<a href="https://fakerjs.dev/" target="_blank">Faker.dev</a>,
8989
<a href="https://github.com/AllMightySauron/ascii-table3" target="_blank">Ascii-Table3</a>,

apps/api/src/fromschema.route.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,32 @@ test('/v1/generate/fromschema rejects invalid seed query value', async () => {
129129
const payload = await response.json();
130130
assert.match(payload.errors?.[0] || '', /seed must be a finite number/i);
131131
});
132+
133+
test('/v1/generate/fromschema applies unit-test defaults for includeSetup', async () => {
134+
try {
135+
const setDefaults = await fetch(url('/v1/generate/options/jest'), {
136+
method: 'POST',
137+
headers: { 'content-type': 'application/json' },
138+
body: JSON.stringify({ options: { includeSetup: true } }),
139+
});
140+
assert.equal(setDefaults.status, 200);
141+
142+
const response = await fetch(url('/v1/generate/fromschema?rowCount=1&outputFormat=jest&responseFormat=rendered'), {
143+
method: 'POST',
144+
headers: { 'content-type': 'text/plain' },
145+
body: 'Name\nBob',
146+
});
147+
148+
assert.equal(response.status, 200);
149+
const body = await response.json();
150+
assert.match(body.rendered, /beforeEach/);
151+
assert.match(body.rendered, /expect\(/);
152+
} finally {
153+
const resetDefaults = await fetch(url('/v1/generate/options/jest/default'), {
154+
method: 'POST',
155+
headers: { 'content-type': 'application/json' },
156+
body: JSON.stringify({}),
157+
});
158+
assert.equal(resetDefaults.status, 200);
159+
}
160+
});

apps/api/src/generate.route.test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import test from 'node:test';
22
import assert from 'node:assert/strict';
33
import http from 'node:http';
44
import { app } from './index.js';
5+
import { generateFromTextSpec } from '@anywaydata/core';
56

67
let server;
78
let port;
@@ -23,6 +24,20 @@ function url(path) {
2324
return `http://127.0.0.1:${port}${path}`;
2425
}
2526

27+
const FRAMEWORKS = [
28+
'junit4',
29+
'junit5',
30+
'junit6',
31+
'testng',
32+
'pytest',
33+
'jest',
34+
'xunit',
35+
'rspec',
36+
'phpunit',
37+
'kotest',
38+
'test-more',
39+
];
40+
2641
test('/v1/generate returns rows payload for valid JSON request', async () => {
2742
const response = await fetch(url('/v1/generate'), {
2843
method: 'POST',
@@ -86,3 +101,39 @@ test('/v1/generate supports responseFormat=raw', async () => {
86101
assert.equal(response.status, 200);
87102
assert.match(response.headers.get('content-type') || '', /text\/csv/i);
88103
});
104+
105+
test('/v1/generate parity: REST rendered matches core for all unit-test frameworks', async () => {
106+
for (const outputFormat of FRAMEWORKS) {
107+
const options = {
108+
options: {
109+
includeSetup: true,
110+
prettyPrint: true,
111+
dataSourceStrategy: 'provider',
112+
},
113+
};
114+
const coreResult = generateFromTextSpec({
115+
textSpec: 'Name\nBob\nAge\n21',
116+
rowCount: 2,
117+
outputFormat,
118+
options,
119+
seed: 123,
120+
});
121+
assert.equal(coreResult.ok, true, `core generation failed for ${outputFormat}`);
122+
123+
const response = await fetch(url('/v1/generate'), {
124+
method: 'POST',
125+
headers: { 'content-type': 'application/json' },
126+
body: JSON.stringify({
127+
textSpec: 'Name\nBob\nAge\n21',
128+
rowCount: 2,
129+
outputFormat,
130+
responseFormat: 'rendered',
131+
options,
132+
seed: 123,
133+
}),
134+
});
135+
assert.equal(response.status, 200, `api status failed for ${outputFormat}`);
136+
const body = await response.json();
137+
assert.equal(body.rendered, coreResult.rendered, `render mismatch for ${outputFormat}`);
138+
}
139+
});

apps/api/src/index.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,28 @@ const UI_OPTION_KEYS_BY_FORMAT = {
106106
],
107107
gherkin: ['showHeadings', 'leftIndent', 'inCellPadding', 'prettyPrint'],
108108
asciitable: ['style'],
109+
junit4: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
110+
junit5: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
111+
junit6: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
112+
testng: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
113+
pytest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
114+
unittest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
115+
nose2: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
116+
jest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
117+
vitest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
118+
mocha: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
119+
xunit: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
120+
nunit: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
121+
mstest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
122+
rspec: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
123+
minitest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
124+
phpunit: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
125+
pest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
126+
kotest: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
127+
'junit5-kotlin': ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
128+
spek: ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
129+
'test-more': ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
130+
'test2-suite': ['suiteName', 'testNamePrefix', 'includeSetup', 'prettyPrint', 'dataSourceStrategy'],
109131
};
110132
const UI_OPTION_TIPS_BY_FORMAT = {
111133
csv: {
@@ -121,6 +143,83 @@ const UI_OPTION_TIPS_BY_FORMAT = {
121143
quoteChar: 'Character used to quote string values.',
122144
escapeChar: 'Character used to escape quote characters inside field values.',
123145
},
146+
junit4: {
147+
suiteName: 'Name of generated Java test class.',
148+
testNamePrefix: 'Prefix for generated test method name.',
149+
includeSetup: 'Include @Before setup scaffold.',
150+
prettyPrint: 'Format generated output for readability.',
151+
dataSourceStrategy: 'Provider/method, inline, or csv source style.',
152+
},
153+
junit5: {
154+
suiteName: 'Name of generated Java test class.',
155+
testNamePrefix: 'Prefix for generated test method name.',
156+
includeSetup: 'Include @BeforeEach setup scaffold.',
157+
prettyPrint: 'Format generated output for readability.',
158+
dataSourceStrategy: 'Provider/method, inline, or csv source style.',
159+
},
160+
junit6: {
161+
suiteName: 'Name of generated Java test class.',
162+
testNamePrefix: 'Prefix for generated test method name.',
163+
includeSetup: 'Include @BeforeEach setup scaffold.',
164+
prettyPrint: 'Format generated output for readability.',
165+
dataSourceStrategy: 'Provider/method, inline, or csv source style.',
166+
},
167+
testng: {
168+
suiteName: 'Name of generated Java test class.',
169+
testNamePrefix: 'Prefix for generated test method name.',
170+
includeSetup: 'Include @BeforeMethod setup scaffold.',
171+
prettyPrint: 'Format generated output for readability.',
172+
dataSourceStrategy: 'Provider/method or inline style.',
173+
},
174+
pytest: {
175+
suiteName: 'Name hint for generated test suite.',
176+
testNamePrefix: 'Prefix for generated test function name.',
177+
includeSetup: 'Include fixture scaffold and inject it into test signature.',
178+
prettyPrint: 'Format generated output for readability.',
179+
dataSourceStrategy: 'Provider function or inline rows.',
180+
},
181+
jest: {
182+
suiteName: 'Name of generated Jest describe block.',
183+
testNamePrefix: 'Prefix for generated test name.',
184+
includeSetup: 'Include beforeEach setup scaffold.',
185+
prettyPrint: 'Format generated output for readability.',
186+
dataSourceStrategy: 'Provider function or inline rows.',
187+
},
188+
xunit: {
189+
suiteName: 'Name of generated C# test class.',
190+
testNamePrefix: 'Prefix for generated test method name.',
191+
includeSetup: 'Include constructor setup scaffold.',
192+
prettyPrint: 'Format generated output for readability.',
193+
dataSourceStrategy: 'MemberData provider or InlineData.',
194+
},
195+
rspec: {
196+
suiteName: 'Name of generated RSpec describe block.',
197+
testNamePrefix: 'Prefix for generated test name.',
198+
includeSetup: 'Include before block scaffold.',
199+
prettyPrint: 'Format generated output for readability.',
200+
dataSourceStrategy: 'Rows constant iteration style.',
201+
},
202+
phpunit: {
203+
suiteName: 'Name of generated PHPUnit test class.',
204+
testNamePrefix: 'Prefix for generated test method name.',
205+
includeSetup: 'Include setUp() scaffold.',
206+
prettyPrint: 'Format generated output for readability.',
207+
dataSourceStrategy: 'Data provider rows style.',
208+
},
209+
kotest: {
210+
suiteName: 'Name of generated Kotest spec class.',
211+
testNamePrefix: 'Prefix for generated test name.',
212+
includeSetup: 'Include beforeTest setup scaffold.',
213+
prettyPrint: 'Format generated output for readability.',
214+
dataSourceStrategy: 'Rows collection iteration style.',
215+
},
216+
'test-more': {
217+
suiteName: 'Name hint for generated Perl test script.',
218+
testNamePrefix: 'Prefix used in assertion labels.',
219+
includeSetup: 'Include setup variable scaffold.',
220+
prettyPrint: 'Format generated output for readability.',
221+
dataSourceStrategy: 'Row hash iteration style.',
222+
},
124223
};
125224

126225
function createExporterForDefaults() {
@@ -138,6 +237,15 @@ function contentTypeForFormat(outputFormat) {
138237
if (format === 'python') return 'text/x-python; charset=utf-8';
139238
if (format === 'java') return 'text/x-java-source; charset=utf-8';
140239
if (format === 'typescript') return 'application/typescript; charset=utf-8';
240+
if (format === 'junit4' || format === 'junit5' || format === 'junit6' || format === 'testng')
241+
return 'text/x-java-source; charset=utf-8';
242+
if (format === 'pytest' || format === 'unittest' || format === 'nose2') return 'text/x-python; charset=utf-8';
243+
if (format === 'jest' || format === 'vitest' || format === 'mocha') return 'text/javascript; charset=utf-8';
244+
if (format === 'xunit' || format === 'nunit' || format === 'mstest') return 'text/x-csharp; charset=utf-8';
245+
if (format === 'rspec' || format === 'minitest') return 'text/x-ruby; charset=utf-8';
246+
if (format === 'phpunit' || format === 'pest') return 'application/x-httpd-php; charset=utf-8';
247+
if (format === 'kotest' || format === 'junit5-kotlin' || format === 'spek') return 'text/x-kotlin; charset=utf-8';
248+
if (format === 'test-more' || format === 'test2-suite') return 'text/x-perl; charset=utf-8';
141249
if (format === 'xml') return 'application/xml; charset=utf-8';
142250
if (format === 'sql') return 'application/sql; charset=utf-8';
143251
if (format === 'gherkin') return 'text/x-gherkin; charset=utf-8';

0 commit comments

Comments
 (0)