diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 795271cab60a..9e15d33f90b3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -11,9 +11,11 @@ jobs: if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - name: Checkout + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 - - uses: Expensify/App/.github/actions/composite/setupNode@main + - name: Setup Node + uses: Expensify/App/.github/actions/composite/setupNode@main - name: Lint JavaScript with ESLint run: npm run lint diff --git a/workflow_tests/assertions/lintAssertions.js b/workflow_tests/assertions/lintAssertions.js new file mode 100644 index 000000000000..3e8862fca63f --- /dev/null +++ b/workflow_tests/assertions/lintAssertions.js @@ -0,0 +1,54 @@ +const utils = require('../utils/utils'); + +const assertLintJobExecuted = (workflowResult, didExecute = true) => { + const steps = [ + utils.getStepAssertion( + 'Checkout', + true, + null, + 'LINT', + 'Checkout', + [], + [], + ), + utils.getStepAssertion( + 'Setup Node', + true, + null, + 'LINT', + 'Setup Node', + [], + [], + ), + utils.getStepAssertion( + 'Lint JavaScript with ESLint', + true, + null, + 'LINT', + 'Lint JavaScript with ESLint', + [], + [{key: 'CI', value: 'true'}], + ), + utils.getStepAssertion( + 'Lint shell scripts with ShellCheck', + true, + null, + 'LINT', + 'Lint shell scripts with ShellCheck', + [], + [], + ), + ]; + + for (const expectedStep of steps) { + if (didExecute) { + expect(workflowResult).toEqual(expect.arrayContaining([expectedStep])); + } else { + expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep])); + } + } +}; + +module.exports = { + assertLintJobExecuted, +}; diff --git a/workflow_tests/lint.test.js b/workflow_tests/lint.test.js new file mode 100644 index 000000000000..6b0669bfbdd4 --- /dev/null +++ b/workflow_tests/lint.test.js @@ -0,0 +1,188 @@ +const path = require('path'); +const kieMockGithub = require('@kie/mock-github'); +const utils = require('./utils/utils'); +const assertions = require('./assertions/lintAssertions'); +const mocks = require('./mocks/lintMocks'); +const eAct = require('./utils/ExtendedAct'); + +jest.setTimeout(60 * 1000); +let mockGithub; +const FILES_TO_COPY_INTO_TEST_REPO = [ + { + src: path.resolve(__dirname, '..', '.github', 'actions'), + dest: '.github/actions', + }, + { + src: path.resolve(__dirname, '..', '.github', 'libs'), + dest: '.github/libs', + }, + { + src: path.resolve(__dirname, '..', '.github', 'scripts'), + dest: '.github/scripts', + }, + { + src: path.resolve(__dirname, '..', '.github', 'workflows', 'lint.yml'), + dest: '.github/workflows/lint.yml', + }, +]; + +describe('test workflow lint', () => { + const githubToken = 'dummy_github_token'; + const actor = 'Dummy Actor'; + beforeEach(async () => { + // create a local repository and copy required files + mockGithub = new kieMockGithub.MockGithub({ + repo: { + testLintWorkflowRepo: { + files: FILES_TO_COPY_INTO_TEST_REPO, + + // if any branches besides main are need add: pushedBranches: ['staging', 'production'], + }, + }, + }); + + await mockGithub.setup(); + }); + + afterEach(async () => { + await mockGithub.teardown(); + }); + describe('event is workflow_call', () => { + const event = 'workflow_call'; + const eventOptions = {}; + it('runs the lint', async () => { + const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; + const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); + let act = new eAct.ExtendedAct(repoPath, workflowPath); + act = utils.setUpActParams( + act, + event, + eventOptions, + {}, + githubToken, + ); + const testMockSteps = { + lint: mocks.LINT__LINT__STEP_MOCKS, + }; + const result = await act + .runEvent(event, { + workflowFile: path.join(repoPath, '.github', 'workflows'), + mockSteps: testMockSteps, + actor, + }); + + assertions.assertLintJobExecuted(result); + }); + describe('actor is OSBotify', () => { + const testActor = 'OSBotify'; + it('runs the lint', async () => { + const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; + const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); + let act = new eAct.ExtendedAct(repoPath, workflowPath); + act = utils.setUpActParams( + act, + event, + eventOptions, + {}, + githubToken, + ); + const testMockSteps = { + lint: mocks.LINT__LINT__STEP_MOCKS, + }; + const result = await act + .runEvent(event, { + workflowFile: path.join(repoPath, '.github', 'workflows'), + mockSteps: testMockSteps, + actor: testActor, + }); + + assertions.assertLintJobExecuted(result); + }); + }); + }); + describe('event is pull_request', () => { + const event = 'pull_request'; + describe('pull_request is opened', () => { + const eventOptions = { + action: 'opened', + }; + it('runs the lint', async () => { + const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; + const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); + let act = new eAct.ExtendedAct(repoPath, workflowPath); + act = utils.setUpActParams( + act, + event, + eventOptions, + {}, + githubToken, + ); + const testMockSteps = { + lint: mocks.LINT__LINT__STEP_MOCKS, + }; + const result = await act + .runEvent(event, { + workflowFile: path.join(repoPath, '.github', 'workflows'), + mockSteps: testMockSteps, + actor, + }); + + assertions.assertLintJobExecuted(result); + }); + describe('actor is OSBotify', () => { + const testActor = 'OSBotify'; + it('does not run the lint', async () => { + const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; + const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); + let act = new eAct.ExtendedAct(repoPath, workflowPath); + act = utils.setUpActParams( + act, + event, + eventOptions, + {}, + githubToken, + ); + const testMockSteps = { + lint: mocks.LINT__LINT__STEP_MOCKS, + }; + const result = await act + .runEvent(event, { + workflowFile: path.join(repoPath, '.github', 'workflows'), + mockSteps: testMockSteps, + actor: testActor, + }); + + assertions.assertLintJobExecuted(result, false); + }); + }); + }); + describe('pull_request is synchronized', () => { + const eventOptions = { + action: 'synchronize', + }; + it('runs the lint', async () => { + const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; + const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); + let act = new eAct.ExtendedAct(repoPath, workflowPath); + act = utils.setUpActParams( + act, + event, + eventOptions, + {}, + githubToken, + ); + const testMockSteps = { + lint: mocks.LINT__LINT__STEP_MOCKS, + }; + const result = await act + .runEvent(event, { + workflowFile: path.join(repoPath, '.github', 'workflows'), + mockSteps: testMockSteps, + actor, + }); + + assertions.assertLintJobExecuted(result); + }); + }); + }); +}); diff --git a/workflow_tests/mocks/lintMocks.js b/workflow_tests/mocks/lintMocks.js new file mode 100644 index 000000000000..de2da8394e5f --- /dev/null +++ b/workflow_tests/mocks/lintMocks.js @@ -0,0 +1,41 @@ +const utils = require('../utils/utils'); + +// lint +const LINT__LINT__CHECKOUT__STEP_MOCK = utils.getMockStep( + 'Checkout', + 'Checkout', + 'LINT', + [], + [], +); +const LINT__LINT__SETUP_NODE__STEP_MOCK = utils.getMockStep( + 'Setup Node', + 'Setup Node', + 'LINT', + [], + [], +); +const LINT__LINT__LINT_JAVASCRIPT_WITH_ESLINT__STEP_MOCK = utils.getMockStep( + 'Lint JavaScript with ESLint', + 'Lint JavaScript with ESLint', + 'LINT', + [], + ['CI'], +); +const LINT__LINT__LINT_SHELL_SCRIPTS_WITH_SHELLCHECK__STEP_MOCK = utils.getMockStep( + 'Lint shell scripts with ShellCheck', + 'Lint shell scripts with ShellCheck', + 'LINT', + [], + [], +); +const LINT__LINT__STEP_MOCKS = [ + LINT__LINT__CHECKOUT__STEP_MOCK, + LINT__LINT__SETUP_NODE__STEP_MOCK, + LINT__LINT__LINT_JAVASCRIPT_WITH_ESLINT__STEP_MOCK, + LINT__LINT__LINT_SHELL_SCRIPTS_WITH_SHELLCHECK__STEP_MOCK, +]; + +module.exports = { + LINT__LINT__STEP_MOCKS, +}; diff --git a/workflow_tests/utils/preGenerateTest.js b/workflow_tests/utils/preGenerateTest.js index 4587705f7c54..80e701945ead 100644 --- a/workflow_tests/utils/preGenerateTest.js +++ b/workflow_tests/utils/preGenerateTest.js @@ -48,7 +48,7 @@ const FILES_TO_COPY_INTO_TEST_REPO = [ ]; describe('test workflow ${workflowName}', () => { - const githubToken = 'dummy_github_token', + const githubToken = 'dummy_github_token'; const actor = 'Dummy Actor'; beforeEach(async () => { // create a local repository and copy required files @@ -68,7 +68,7 @@ describe('test workflow ${workflowName}', () => { afterEach(async () => { await mockGithub.teardown(); }); - test('test stub', async () => { + it('test stub', async () => { const repoPath = mockGithub.repo.getPath('test${capitalize(workflowName)}WorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', '${workflowName}.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath);