Files
languageservices/languageservice/src/context-providers/needs.test.ts
T
eric sciple 656a821a94 ESM migration: Add .js extensions for node16 moduleResolution (#257)
Migrate expressions, workflow-parser, and languageservice packages to use
proper ESM imports with .js extensions that work with node16 moduleResolution.

Changes:
- Update tsconfig.build.json in each package to use module: node16 and
  moduleResolution: node16
- Add .js extensions to all relative import paths (Option B approach)
- Fix yaml internal type imports in workflow-parser by defining local types
- Add skipLibCheck to handle @types/node compatibility issues
- Add TypeScript 5.8.3 override in root package.json
- Add ESM migration plan documentation

The languageserver package is deferred due to test hang issues that need
further investigation.

Related #154 - Upgrade moduleResolution from node to node16 or nodenext
Related #110 - Published ESM code has imports without file extensions
Related #64 - expressions: ERR_MODULE_NOT_FOUND attempting to run example
Related #146 - Can not import @actions/workflow-parser

Test results:
- expressions: 1068 tests passed
- workflow-parser: 292 tests passed
- languageservice: 452 tests passed

* docs: update ESM migration plan with findings

- Update languageserver blocker: vscode-languageserver v8.0.2 lacks ESM
  exports (not a test hang issue)
- Document that Option B (manual .js extensions) was chosen over Option A
  due to ts-jest compatibility issues
- Add workaround for yaml package internal types (LinePos, NodeBase)
- Update migration status table with accurate reason for deferral
- Add skipLibCheck note for @types/node compatibility
2025-12-18 13:35:48 -06:00

142 lines
3.7 KiB
TypeScript

import {DescriptionDictionary} from "@actions/expressions";
import {StringData} from "@actions/expressions/data/string";
import {WorkflowContext} from "../context/workflow-context.js";
import {testGetWorkflowContext} from "../test-utils/test-workflow-context.js";
import {getNeedsContext} from "./needs.js";
describe("needs context", () => {
describe("invalid workflow context", () => {
it("jobs not defined", () => {
const workflowContext = {} as WorkflowContext;
expect(workflowContext.job).toBeUndefined();
expect(workflowContext.reusableWorkflowJob).toBeUndefined();
const context = getNeedsContext(workflowContext);
expect(context).toEqual(new DescriptionDictionary());
});
});
it("job without needs", async () => {
const workflowContext = await testGetWorkflowContext(`on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: ec|ho`);
const context = getNeedsContext(workflowContext);
expect(context).toEqual(new DescriptionDictionary());
});
it("job with needs", async () => {
const workflowContext = await testGetWorkflowContext(`on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo
build:
runs-on: ubuntu-latest
needs: [test]
steps:
- run: ec|ho`);
const context = getNeedsContext(workflowContext);
expect(context.pairs().map(x => x.key)).toEqual(["test"]);
});
it("reusable job without needs", async () => {
const workflowContext = await testGetWorkflowContext(`on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo
build:
uses: ./.github/workflows/some-reusable-wor|kflow.yml`);
const context = getNeedsContext(workflowContext);
expect(context).toEqual(new DescriptionDictionary());
});
it("reusable job with needs", async () => {
const workflowContext = await testGetWorkflowContext(`on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo
build:
uses: ./.github/workflows/some-reusable-wor|kflow.yml
needs: [test]`);
const context = getNeedsContext(workflowContext);
expect(context.pairs().map(x => x.key)).toEqual(["test"]);
});
describe("outputs", () => {
it("regular job with outputs", async () => {
const workflowContext = await testGetWorkflowContext(`
on: push
jobs:
a:
outputs:
build_id: my-build-id
runs-on: ubuntu-latest
steps:
- run: echo
b:
uses: ./.github/workflows/some-reusable-wor|kflow.yml
needs: [a]
`);
const context = getNeedsContext(workflowContext);
const needs = context.get("a") as DescriptionDictionary;
expect(needs).toBeDefined();
const outputs = needs.get("outputs") as DescriptionDictionary;
expect(outputs).toBeDefined();
expect(outputs.pairs()).toEqual([
{
key: "build_id",
value: new StringData("my-build-id"),
description: undefined
}
]);
});
it("reusable job with outputs", async () => {
const workflowContext = await testGetWorkflowContext(`
on: push
jobs:
a:
uses: ./.github/workflows/reusable-workflow-with-outputs.yaml
b:
needs: [a]
runs-on: ubuntu-latest
steps:
- run: ec|ho
`);
const context = getNeedsContext(workflowContext);
const needs = context.get("a") as DescriptionDictionary;
expect(needs).toBeDefined();
const outputs = needs.get("outputs") as DescriptionDictionary;
expect(outputs).toBeDefined();
expect(outputs.pairs().map(x => x.key)).toEqual(["build_id"]);
expect(outputs.pairs()).toEqual([
{
key: "build_id",
value: new StringData("123"),
description: "The resulting build ID"
}
]);
});
});
});