Skip to content

Commit fcd3f41

Browse files
rcosta358codex
andauthored
Test passing fixtures and minimum supported VS Code (#145)
Add an isolated passing workspace and assert the first diagnostic result after Verify. Run both passing and failing fixtures on stable and the minimum supported VS Code (1.82.0) for every pull request, main, and reusable release check. Validated fixture failure reporting, workflow coverage, lint, types, and extension installation. Depends on #144. Closes #132. 🤖 Generated with [Codex](https://openai.com/codex/) --------- Co-authored-by: Codex <noreply@openai.com>
1 parent 54cd1bd commit fcd3f41

6 files changed

Lines changed: 66 additions & 32 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,12 @@ jobs:
7878
if-no-files-found: error
7979
retention-days: 1
8080
integration:
81-
name: VS Code integration
81+
name: VS Code integration (${{ matrix.version }})
8282
runs-on: ubuntu-latest
83+
strategy:
84+
fail-fast: false
85+
matrix:
86+
version: [stable, minimum]
8387

8488
defaults:
8589
run:
@@ -109,15 +113,16 @@ jobs:
109113
- name: Build server
110114
run: npm run build:server
111115

112-
- name: Run VS Code stable smoke test
116+
- name: Run VS Code fixture tests
113117
env:
114118
JAVA_HOME: ${{ steps.java.outputs.path }}
119+
VSCODE_TEST_VERSION: ${{ matrix.version }}
115120
run: xvfb-run -a npm test
116121

117122
- name: Upload VS Code logs
118123
if: failure()
119124
uses: actions/upload-artifact@v4
120125
with:
121-
name: vscode-logs
126+
name: vscode-logs-${{ matrix.version }}
122127
path: client/.vscode-test/user-data/logs
123128
if-no-files-found: ignore

‎client/.vscode-test.mjs‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1+
import { readFileSync } from 'node:fs';
12
import { defineConfig } from '@vscode/test-cli';
3+
import { minVersion } from 'semver';
24

3-
export default defineConfig({
4-
files: 'out/test/**/*.test.js',
5-
version: 'stable',
6-
workspaceFolder: 'test-fixtures/failing',
5+
const { engines } = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
6+
const version = process.env.VSCODE_TEST_VERSION === 'minimum'
7+
? minVersion(engines.vscode).version
8+
: 'stable';
9+
10+
export default defineConfig(['failing', 'passing'].map(fixture => ({
11+
label: fixture,
12+
files: fixture === 'failing' ? 'out/test/**/*.test.js' : 'out/test/smoke.test.js',
13+
version,
14+
workspaceFolder: `test-fixtures/${fixture}`,
715
extensionDevelopmentPath: '.',
816
launchArgs: ['--disable-extensions', '--disable-workspace-trust'],
917
mocha: { ui: 'tdd', timeout: 120_000 },
10-
});
18+
})));

‎client/package-lock.json‎

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎client/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,15 @@
172172
"@types/jsdom": "^30.0.0",
173173
"@types/mocha": "^10.0.10",
174174
"@types/node": "^24.7.2",
175-
"@types/vscode": "^1.82.0",
175+
"@types/vscode": "~1.82.0",
176176
"@vscode/test-cli": "^0.0.15",
177177
"@vscode/test-electron": "^3.1.0",
178178
"@vscode/vsce": "^3.0.0",
179179
"eslint": "^9.39.0",
180180
"jsdom": "^30.1.1",
181181
"jsonc-parser": "^0.4.2",
182182
"minimist": "^1.2.7",
183+
"semver": "^7.7.4",
183184
"ts-loader": "^9.5.4",
184185
"typescript": "~5.3.0",
185186
"typescript-eslint": "^8.0.0",

‎client/src/test/smoke.test.ts‎

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { LJDiagnostic } from '../types/diagnostics';
55
import type { LiquidJavaTestApi } from '../types/test-api';
66

77
suite('Bundled LiquidJava extension', () => {
8-
test('activates, becomes ready, and verifies the failing fixture', async () => {
8+
test('activates, becomes ready, and verifies its isolated fixture', async () => {
99
const installed = vscode.extensions.getExtension<LiquidJavaTestApi>('AlcidesFonseca.liquid-java');
1010
assert.ok(installed, 'LiquidJava must be loaded in the Extension Host');
1111
assert.equal(installed.packageJSON.main, './dist/extension.js');
@@ -16,17 +16,25 @@ suite('Bundled LiquidJava extension', () => {
1616
assert.notEqual(api.getState().status, 'stopped');
1717

1818
const workspace = vscode.workspace.workspaceFolders?.[0];
19-
assert.ok(workspace, 'the failing fixture must have its own workspace');
20-
const uri = vscode.Uri.joinPath(workspace.uri, 'src/main/java/FailingRefinement.java');
19+
assert.ok(workspace, 'the fixture must have its own workspace');
20+
const passing = path.basename(workspace.uri.fsPath) === 'passing';
21+
const file = passing ? 'PassingRefinement.java' : 'FailingRefinement.java';
22+
const uri = vscode.Uri.joinPath(workspace.uri, `src/main/java/${file}`);
2123
const subscriptions: vscode.Disposable[] = [];
22-
const nextFixtureDiagnostics = () => new Promise<LJDiagnostic[]>((resolve) => {
23-
const subscription = api.onDiagnostics((diagnostics) => {
24-
if (diagnostics.some(d => d.type === 'refinement-error' && path.resolve(d.file) === uri.fsPath)) {
25-
subscription.dispose();
26-
resolve(diagnostics);
27-
}
24+
const nextFixtureDiagnostics = () => new Promise<LJDiagnostic[]>((resolve, reject) => {
25+
const dispose = () => {
26+
diagnosticsSubscription.dispose();
27+
failureSubscription.dispose();
28+
};
29+
const diagnosticsSubscription = api.onDiagnostics((diagnostics) => {
30+
dispose();
31+
resolve(diagnostics);
2832
});
29-
subscriptions.push(subscription);
33+
const failureSubscription = api.onFailure(() => {
34+
dispose();
35+
reject(new Error(`LiquidJava verifier crashed while checking ${file} (status: ${api.getState().status})`));
36+
});
37+
subscriptions.push(diagnosticsSubscription, failureSubscription);
3038
});
3139
try {
3240
// settle automatic verification before testing the manual command
@@ -38,12 +46,17 @@ suite('Bundled LiquidJava extension', () => {
3846
const manualDiagnostics = nextFixtureDiagnostics();
3947
await vscode.commands.executeCommand('liquidjava.verify');
4048
const diagnostics = await manualDiagnostics;
41-
const error = diagnostics.find(d => d.type === 'refinement-error' && path.resolve(d.file) === uri.fsPath);
42-
assert.ok(error);
43-
assert.equal(error.category, 'error');
44-
assert.equal(error.title, 'Refinement Error');
45-
assert.ok(error.position, 'the diagnostic must identify the invalid assignment');
46-
assert.equal(api.getState().status, 'failed');
49+
if (passing) {
50+
assert.deepEqual(diagnostics, [], 'correct code must emit an explicit empty result');
51+
assert.equal(api.getState().status, 'passed');
52+
} else {
53+
const error = diagnostics.find(d => d.type === 'refinement-error' && vscode.Uri.file(path.resolve(d.file)).fsPath === uri.fsPath);
54+
assert.ok(error, `expected a refinement error for ${file}; received ${JSON.stringify(diagnostics)}`);
55+
assert.equal(error.category, 'error');
56+
assert.equal(error.title, 'Refinement Error');
57+
assert.ok(error.position, 'the diagnostic must identify the invalid assignment');
58+
assert.equal(api.getState().status, 'failed');
59+
}
4760
assert.deepEqual(api.getState().diagnostics, diagnostics);
4861
} finally {
4962
subscriptions.forEach(subscription => subscription.dispose());
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import liquidjava.specification.Refinement;
2+
3+
public class PassingRefinement {
4+
@Refinement("_ > 0")
5+
int positive = 1;
6+
}

0 commit comments

Comments
 (0)