Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 0 additions & 35 deletions .github/workflows/test-action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,47 +51,12 @@ jobs:
wait-for-results: "yes"
domain: "https://api-staging.heal.dev"
comment-on-pr: "yes"
- name: Run Action
id: my-action_new
uses: ./
with:
api-token: ${{ secrets.HEAL_API_TOKEN }}
suite: "wen/trigger"
test-config: |
{
"entrypoint": "https://www.wikipedia.org/",
"variables": {
"hello": "test level"
}
}
stories: |
[
{
"slug": "new-test",
"test-config": {
"entrypoint": "https://www.ikea.com/fr/fr/",
"variables": {
"hello": "story level"
}
}
}
]
wait-for-results: "yes"
domain: "https://api-staging.heal.dev"

- name: Run Action
id: my-action_new_with_test_config
uses: ./
with:
api-token: ${{ secrets.HEAL_API_TOKEN }}
suite: "wen/trigger"
test-config: |
{
"entrypoint": "https://www.wikipedia.org/",
"variables": {
"hello": "you"
}
}
stories: |
[
{
Expand Down
28 changes: 20 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const core = require('@actions/core');
const { context, getOctokit } = require('@actions/github');

async function parseJsonResponse(response) {
const text = await response.text();
if (!text || text.trim() === '') return null;
return JSON.parse(text);
}

async function createTestSummary(results, url) {
const { runs, projectName, suiteName } = results;
Expand Down Expand Up @@ -294,16 +299,19 @@ async function run() {
throw new Error(`HTTP error! status: ${triggerResponse.status}`);
}

const triggerData = await triggerResponse.json();
const { executionId, url } = triggerData;
const triggerData = await parseJsonResponse(triggerResponse);
const executionId = triggerData?.executionId;
const url = triggerData?.url;

core.info(`Execution started with ID ${executionId}.`);
core.info(`execution-url: ${url}`);
core.setOutput('execution-id', executionId);
core.setOutput('execution-url', url);
if (executionId != null && url != null) {
core.info(`Execution started with ID ${executionId}.`);
core.info(`execution-url: ${url}`);
core.setOutput('execution-id', executionId);
core.setOutput('execution-url', url);
}

// Decide whether to wait for results
if (waitForResults.toLowerCase() === 'yes' || waitForResults.toLowerCase() === 'true') {
if (executionId != null && url != null && (waitForResults.toLowerCase() === 'yes' || waitForResults.toLowerCase() === 'true')) {
core.info(`Waiting for execution ${executionId} to finish...`);

let status = 'running';
Expand Down Expand Up @@ -331,7 +339,11 @@ async function run() {
throw new Error(`HTTP error! status: ${executionResponse.status}`);
}

const report = await executionResponse.json();
const report = await parseJsonResponse(executionResponse);
if (report == null) {
core.info('Execution status: no body, stopping wait.');
break;
}

status = report.status;
core.info(`Execution status: ${status}`);
Expand Down
78 changes: 74 additions & 4 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,20 @@ describe('GitHub Action Tests', () => {

describe('run', () => {
beforeEach(() => {
// Mock fetch globally
// Mock fetch globally (parseJsonResponse uses text())
global.fetch = jest.fn().mockImplementation((url) => {
if (url.includes('/trigger')) {
return Promise.resolve({
ok: true,
json: () => Promise.resolve({
text: () => Promise.resolve(JSON.stringify({
executionId: 'test-execution',
url: 'http://test.com/execution'
})
}))
});
}
return Promise.resolve({
ok: true,
json: () => Promise.resolve(mockResults)
text: () => Promise.resolve(JSON.stringify(mockResults))
});
});
});
Expand Down Expand Up @@ -203,6 +203,76 @@ describe('GitHub Action Tests', () => {
expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('API Error'));
});

it('should fail on HTTP error status from trigger', async () => {
core.getInput = jest.fn().mockImplementation((name) => {
if (name === 'suite-id') return 'test-suite-id';
if (name === 'payload') return JSON.stringify({ stories: [{ id: 1, entryHref: 'http://example.com' }] });
return null;
});
global.fetch = jest.fn().mockResolvedValue({
ok: false,
status: 500,
text: () => Promise.resolve('')
});

await run();

expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('HTTP error! status: 500'));
});

it('should not fail when trigger response has empty body (fail only on HTTP status)', async () => {
core.getInput = jest.fn().mockImplementation((name) => {
if (name === 'suite-id') return 'test-suite-id';
if (name === 'payload') return JSON.stringify({ stories: [{ id: 1, entryHref: 'http://example.com' }] });
return null;
});
global.fetch = jest.fn().mockImplementation((url) => {
if (url.includes('/trigger')) {
return Promise.resolve({
ok: true,
text: () => Promise.resolve('')
});
}
return Promise.resolve({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResults))
});
});

await run();

expect(core.setFailed).not.toHaveBeenCalled();
});

it('should not fail when execution status response has empty body, stop polling', async () => {
core.getInput = jest.fn().mockImplementation((name) => {
if (name === 'suite-id') return 'test-suite-id';
if (name === 'payload') return JSON.stringify({ stories: [{ id: 1, entryHref: 'http://example.com' }] });
return null;
});
global.fetch = jest.fn().mockImplementation((url) => {
if (url.includes('/trigger')) {
return Promise.resolve({
ok: true,
text: () => Promise.resolve(JSON.stringify({
executionId: 'test-execution',
url: 'http://test.com/execution'
}))
});
}
return Promise.resolve({
ok: true,
text: () => Promise.resolve('')
});
});

await run();

expect(core.setFailed).not.toHaveBeenCalled();
const executionCalls = global.fetch.mock.calls.filter(call => call[0].includes('/execution/'));
expect(executionCalls.length).toBe(1);
}, 20000);

it('should handle invalid JSON payload', async () => {
core.getInput = jest.fn().mockImplementation((name) => {
if (name === 'payload') return 'invalid-json';
Expand Down
Loading