diff --git a/.github/workflows/pr-workflow.yaml b/.github/workflows/pr-workflow.yaml index 534b8405..68ff3e48 100644 --- a/.github/workflows/pr-workflow.yaml +++ b/.github/workflows/pr-workflow.yaml @@ -6,7 +6,7 @@ jobs: name: Mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@main - name: Install dependencies run: npm ci @@ -29,4 +29,11 @@ jobs: with: application-id: D6uz-lhAGBYuTTc6Jj_w0Q-a environment-id: I9tfo2dWd7WSigXcO91feA-e - browser-types: chrome + browser-types: | + chrome + plan-labels: | + canary + smoke-test + http-headers: | + X-Test-Header-1: 1234 + X-Test-Header-2: 5678 \ No newline at end of file diff --git a/.github/workflows/push-workflow.yaml b/.github/workflows/push-workflow.yaml index 2253bd28..141a7460 100644 --- a/.github/workflows/push-workflow.yaml +++ b/.github/workflows/push-workflow.yaml @@ -7,7 +7,7 @@ jobs: name: Mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@main - name: Install dependencies run: npm ci @@ -30,4 +30,12 @@ jobs: with: application-id: D6uz-lhAGBYuTTc6Jj_w0Q-a environment-id: I9tfo2dWd7WSigXcO91feA-e - browser-types: chrome + browser-types: | + chrome + plan-labels: | + canary + smoke-test + http-headers: | + X-Test-Header-1: 1234 + X-Test-Header-2: 5678 + diff --git a/README.md b/README.md index 6c5d7430..9cd4317c 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ test runs associated with that deployment and waiting for their results. For more complex use cases, see the [setup-mabl-cli](https://github.com/marketplace/actions/setup-mabl-cli) Action to access the CLI directly. -### Example workflow: +### Example workflow: Simple ``` on: [push] -name: mabl +name: mabl Simple Example jobs: test: @@ -32,6 +32,50 @@ jobs: environment-id: ``` +### Example workflow: Complete + +Using all available flags. + +``` +on: [push] + +name: mabl Complex Example + +jobs: + test: + name: mabl Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Functional test deployment + id: mabl-test-deployment + uses: mablhq/github-run-tests-action@v1 + env: + MABL_API_KEY: ${{ secrets.MABL_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + application-id: + environment-id: + uri: + mabl-branch: + # Runs for both browsers + browser-types: | + chrome + firefox + # Runs plans matching ANY of the following labels AND the environment/application IDs above + plan-labels: | + canary + smoke-test + http-headers: | + My-Header:the-value + My-Other-Header:the-second-value + continue-on-failure: true + rebaseline-images: true + set-static-baseline: true + event-time: +``` + ### Environment variables - `MABL_API_KEY` {string} - Your mabl API key @@ -55,18 +99,21 @@ jobs: Use the [curl builder](https://app.mabl.com/workspaces/-/settings/apis#api-docs-selector-dropdown-button) to find the id. -- `browser-types` {string} {optional}: comma separated override for browser +- `browser-types` {string} (optional): comma or new line separated override for browser types to test e.g. `chrome, firefox, safari, internet_explorer`. If not provided, mabl will test the browsers configured on the triggered test. -- `uri` {string} {optional} the base uri to test against. If provided, this will +- `plan-labels` {string} (optional): comma or new line separated plan labels to test. Plans matching **any** label will be run. e.g. `smoke-test, beta-feature`. Note: additional selection criteria must also be met like application-id or environment-id, if supplied. +- `uri` {string} (optional) the base uri to test against. If provided, this will override the default uri associated with the environment in mabl +- `mabl-branch` {string} (optional) run tests on the mabl branch of tests with this name. Defaults to `master`. +- `http-headers` {string} (optional) Headers to add to all requests e.g. "My-Header:the-value" (comma or new line delimited). - `rebaseline-images` {boolean} (optional) - Set `true` to reset the visual baseline to the current deployment -- `set-static-baseline` {boolean} {optional} - Set `true` to use current +- `set-static-baseline` {boolean} (optional) - Set `true` to use current deployment as an exact static baseline. If set, mabl will **not** model dynamic areas and will use the current deployment as the pixel-exact visual baseline. -- `continue-on-failure` {boolean} {optional} - Set to true to continue the build +- `continue-on-failure` {boolean} (optional) - Set to true to continue the build even if there are test failures - `event-time` {int64} (optional) - Event time the deployment occurred in UTC epoch milliseconds. Defaults to now. diff --git a/action.yml b/action.yml index 1374817c..1078899f 100644 --- a/action.yml +++ b/action.yml @@ -6,26 +6,38 @@ branding: inputs: application-id: description: ^ - 'the mabl id for the deployed application. You can get the id using the + 'Mabl id for the deployed application. You can get the id using the curl builder at https://app.mabl.com/workspaces/-/settings/apis. Either this or environment-id must be provided' required: false environment-id: description: ^ - 'the mabl id for the deployed environment. You can get the id using the + 'Mabl id for the deployed environment. You can get the id using the curl builder at https://app.mabl.com/workspaces/-/settings/apis. Either this or application-id must be provided' required: false browser-types: description: ^ - 'override for the browser types to test (comma separated). If not provided, mabl will test - the browsers configured on the triggered test plans.' + 'Override browser types to test. If not provided, mabl will test + the browsers configured on the triggered test plans (comma or new line delimited).' + required: false + plan-labels: + description: ^ + 'Include all plans with ANY of the supplied labels (comma or new line delimited).' required: false uri: description: ^ - 'the base uri to test against. If provided, this will override the default uri + 'Base URI to test against. If provided, this will override the default URI associated with the environment in mabl' required: false + mabl-branch: + description: ^ + 'Run tests on the mabl branch of tests with this name. Defaults to "master".' + required: false + http-headers: + description: ^ + 'Headers to add to all requests e.g. "My-Header:the-value" (comma or new line delimited).' + required: false rebaseline-images: description: ^ 'Set to true to reset the visual baseline to the current deployment' @@ -44,23 +56,23 @@ inputs: required: false default: false event-time: - description: "The event time the deployment happened at. Defaults to now." + description: "Event time the deployment occurred. Defaults to now." required: false outputs: mabl-deployment-id: - description: "mabl deployment event id" + description: "Mabl deployment event id" plans_run: - description: "total number of mabl plans run against this deployment. A mabl plan is a collection of similarly configured tests." + description: "Total number of mabl plans run against this deployment. A mabl plan is a collection of similarly configured tests." plans_passed: - description: "number of mabl plans that passed against this deployment. A mabl plan is a collection of similarly configured tests." + description: "Number of mabl plans that passed against this deployment. A mabl plan is a collection of similarly configured tests." plans_failed: - description: "number of mabl plans that failed against this deployment. A mabl plan is a collection of similarly configured tests." + description: "Number of mabl plans that failed against this deployment. A mabl plan is a collection of similarly configured tests." tests_run: - description: "total number of mabl tests run against this deployment." + description: "Total number of mabl tests run against this deployment." tests_passed: - description: "number of mabl tests that passed against this deployment." + description: "Number of mabl tests that passed against this deployment." tests_failed: - description: "number of mabl tests that failed against this deployment." + description: "Number of mabl tests that failed against this deployment." runs: using: "node12" diff --git a/package.json b/package.json index 4e09d2ff..c548fef7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mabl-github-deployments-action", - "version": "1.9.0", + "version": "1.10.0", "description": "mabl github action for GitHub pipelines integration", "main": "lib/src/index.js", "scripts": { diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 00000000..5fd2a2e4 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,26 @@ +export const USER_AGENT = 'mabl-github-run-tests-action'; + +export enum ActionInputs { + ApplicationId = 'application-id', + BrowserTypes = 'browser-types', + ContinueOnFailure = 'continue-on-failure', + EnvironmentId = 'environment-id', + EventTime = 'event-time', + HttpHeaders = 'http-headers', + MablBranch = 'mabl-branch', + PlanLabels = 'plan-labels', + RebaselineImages = 'rebaseline-images', + SetStaticBaseline = 'set-static-baseline', + Uri = 'uri', +} + +export enum ActionOutputs { + DeploymentId = 'mabl-deployment-id', + // Note: from here down is snake case, not dash case + PlansRun = 'plans_run', + PlansPassed = 'plans_passed', + PlansFailed = 'plans_failed', + TestsRun = 'tests_run', + TestsPassed = 'tests_passed', + TestsFailed = 'tests_failed', +} diff --git a/src/entities/Environment.ts b/src/entities/Environment.ts new file mode 100644 index 00000000..687192a0 --- /dev/null +++ b/src/entities/Environment.ts @@ -0,0 +1,9 @@ +export interface Environment { + id: string; + created_time: number; + created_by_id: string; + last_updated_time: number; + last_updated_by_id: string; + organization_id: string; + name: string; +} diff --git a/src/index.ts b/src/index.ts index c514736a..a1685cc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,9 +11,11 @@ import {prettyFormatExecution} from './table'; import * as core from '@actions/core'; import * as github from '@actions/github'; import {Option} from './interfaces'; +import {Environment} from './entities/Environment'; +import {ActionInputs, ActionOutputs, USER_AGENT} from './constants'; const DEFAULT_MABL_APP_URL = 'https://app.mabl.com'; -const EXECUTION_POLL_INTERVAL_MILLIS = 10000; +const EXECUTION_POLL_INTERVAL_MILLIS = 10_000; const EXECUTION_COMPLETED_STATUSES = [ 'succeeded', 'failed', @@ -23,45 +25,65 @@ const EXECUTION_COMPLETED_STATUSES = [ ]; const GITHUB_BASE_URL = 'https://api.github.com'; -async function run(): Promise { +export function optionalArrayInput(name: string): string[] { + // Note: GitHub Action inputs default to '' for undefined inputs, remove these + return core + .getInput(name, { + required: false, + }) + .split(/[,\n]/) + .filter((item) => item.length) + .map((item) => item.trim()); +} + +export function optionalInput(name: string): string | undefined { + const rawValue = core.getInput(name, { + required: false, + }); + + if (rawValue.length > 0) { + return rawValue; + } + return; +} + +export function booleanInput(name: string): boolean { + return ( + core + .getInput(name, { + required: false, + }) + .toLowerCase() === 'true' + ); +} + +export async function run(): Promise { try { core.startGroup('Gathering inputs'); - const applicationId: string = core.getInput('application-id', { - required: false, - }); - const environmentId: string = core.getInput('environment-id', { - required: false, - }); + const applicationId = optionalInput(ActionInputs.ApplicationId); + const environmentId = optionalInput(ActionInputs.EnvironmentId); - const apiKey: string = process.env.MABL_API_KEY || ''; + const apiKey = process.env.MABL_API_KEY; if (!apiKey) { - core.setFailed('MABL_API_KEY required'); + core.setFailed('env var MABL_API_KEY required'); + return; } + const planLabels = optionalArrayInput(ActionInputs.PlanLabels); + // plan override options - const browserTypes: string = core.getInput('browser-types', { - required: false, - }); - const uri: string = core.getInput('uri', {required: false}); + const browserTypes = optionalArrayInput(ActionInputs.BrowserTypes); + const httpHeaders = optionalArrayInput(ActionInputs.HttpHeaders); + const uri = optionalInput(ActionInputs.Uri); + const mablBranch = optionalInput(ActionInputs.MablBranch); // deployment action options - const rebaselineImages: boolean = parseBoolean( - core.getInput('rebaseline-images', { - required: false, - }), - ); - const setStaticBaseline: boolean = parseBoolean( - core.getInput('set-static-baseline', { - required: false, - }), - ); - - const continueOnPlanFailure: boolean = parseBoolean( - core.getInput('continue-on-failure', {required: false}), - ); + const rebaselineImages = booleanInput(ActionInputs.RebaselineImages); + const setStaticBaseline = booleanInput(ActionInputs.SetStaticBaseline); + const continueOnPlanFailure = booleanInput(ActionInputs.ContinueOnFailure); const pullRequest = await getRelatedPullRequest(); - const eventTimeString = core.getInput('event-time', {required: false}); + const eventTimeString = optionalInput(ActionInputs.EventTime); const eventTime = eventTimeString ? parseInt(eventTimeString) : Date.now(); let properties: DeploymentProperties = { @@ -92,6 +114,10 @@ async function run(): Promise { ? github.context.payload.pull_request?.head?.sha : process.env.GITHUB_SHA; + if (mablBranch) { + core.info(`Using mabl branch [${mablBranch}]`); + } + core.info(`Using git revision [${revision}]`); core.endGroup(); @@ -101,28 +127,40 @@ async function run(): Promise { // send the deployment const deployment: Deployment = await apiClient.postDeploymentEvent( - applicationId, - environmentId, browserTypes, - uri, + planLabels, + httpHeaders, rebaselineImages, setStaticBaseline, - revision, eventTime, properties, + applicationId, + environmentId, + uri, + revision, + mablBranch, ); - core.setOutput('mabl-deployment-id', deployment.id); + core.setOutput(ActionOutputs.DeploymentId, deployment.id); - let outputLink: string = baseApiUrl; + let appOrEnv: Application | Environment | undefined; if (applicationId) { - const application: Application = await apiClient.getApplication( - applicationId, + appOrEnv = await apiClient.getApplication(applicationId); + } else if (environmentId) { + appOrEnv = await apiClient.getEnvironment(environmentId); + } + + // Check we have minimum viable config + if (!appOrEnv) { + core.setFailed( + 'Invalid configuration. Valid "application-id" or "environment-id" must be set. No tests started.', ); - outputLink = `${baseApiUrl}/workspaces/${application.organization_id}/events/${deployment.id}`; - core.info(`Deployment triggered. View output at: ${outputLink}`); + return; // exit } + const outputLink = `${baseApiUrl}/workspaces/${appOrEnv.organization_id}/events/${deployment.id}`; + core.info(`Deployment triggered. View output at: ${outputLink}`); + core.startGroup('Await completion of tests'); // poll Execution result until complete @@ -161,27 +199,27 @@ async function run(): Promise { }); core.setOutput( - 'plans_run', + ActionOutputs.PlansRun, '' + finalExecutionResult.plan_execution_metrics.total, ); core.setOutput( - 'plans_passed', + ActionOutputs.PlansPassed, '' + finalExecutionResult.plan_execution_metrics.passed, ); core.setOutput( - 'plans_failed', + ActionOutputs.PlansFailed, '' + finalExecutionResult.plan_execution_metrics.failed, ); core.setOutput( - 'tests_run', + ActionOutputs.TestsRun, '' + finalExecutionResult.journey_execution_metrics.total, ); core.setOutput( - 'tests_passed', + ActionOutputs.TestsPassed, '' + finalExecutionResult.journey_execution_metrics.passed, ); core.setOutput( - 'tests_failed', + ActionOutputs.TestsFailed, '' + finalExecutionResult.journey_execution_metrics.failed, ); @@ -205,10 +243,6 @@ async function run(): Promise { } } -function parseBoolean(toParse: string): boolean { - return toParse?.toLowerCase() === 'true'; -} - function getExecutionsStillPending( executionResult: ExecutionResult, ): Execution[] { @@ -233,7 +267,7 @@ async function getRelatedPullRequest(): Promise> { Authorization: `token ${githubToken}`, Accept: 'application/vnd.github.groot-preview+json', 'Content-Type': 'application/json', - 'User-Agent': 'mabl-action', + 'User-Agent': USER_AGENT, }, }; const client = axios.create(config); diff --git a/src/mablApiClient.ts b/src/mablApiClient.ts index 87be8c8e..ae6c72a8 100644 --- a/src/mablApiClient.ts +++ b/src/mablApiClient.ts @@ -3,6 +3,8 @@ import {Application} from './entities/Application'; import {Deployment, DeploymentProperties} from './entities/Deployment'; import {ExecutionResult} from './entities/ExecutionResult'; import axios, {AxiosInstance, AxiosRequestConfig} from 'axios'; +import {Environment} from './entities/Environment'; +import {USER_AGENT} from './constants'; export class MablApiClient { private readonly httpClient: AxiosInstance; @@ -12,7 +14,7 @@ export class MablApiClient { constructor(apiKey: string) { const config: AxiosRequestConfig = { headers: { - 'User-Agent': 'github-run-tests-action', + 'User-Agent': USER_AGENT, Accept: 'application/json', 'Content-Type': 'application/json', }, @@ -58,14 +60,26 @@ export class MablApiClient { ); } - async getApplication(applicationId: string): Promise { + async getApplication(id: string): Promise { try { return await this.makeGetRequest( - `${this.baseUrl}/v1/applications/${applicationId}`, + `${this.baseUrl}/v1/applications/${id}`, ); } catch (error) { throw new Error( - `failed to get mabl application ($applicationId) from the API ${error}`, + `failed to get mabl application (${id}) from the API ${error}`, + ); + } + } + + async getEnvironment(id: string): Promise { + try { + return await this.makeGetRequest( + `${this.baseUrl}/v1/environments/${id}`, + ); + } catch (error) { + throw new Error( + `failed to get mabl environment (${id}) from the API ${error}`, ); } } @@ -83,27 +97,33 @@ export class MablApiClient { } async postDeploymentEvent( - applicationId: string, - environmentId: string, - browserTypes: string, - uri: string, + browserTypes: string[], + planLabels: string[], + httpHeaders: string[], rebaselineImages: boolean, setStaticBaseline: boolean, - revision: string | undefined, eventTime: number, properties: DeploymentProperties, + applicationId?: string, + environmentId?: string, + uri?: string, + revision?: string, + mablBranch?: string, ): Promise { try { const requestBody: any = this.buildRequestBody( - applicationId, - environmentId, browserTypes, - uri, + planLabels, + httpHeaders, rebaselineImages, setStaticBaseline, eventTime, properties, + applicationId, + environmentId, + uri, revision, + mablBranch, ); return await this.makePostRequest( `${this.baseUrl}/events/deployment/`, @@ -115,15 +135,18 @@ export class MablApiClient { } buildRequestBody( - applicationId: string, - environmentId: string, - browserTypes: string, - uri: string, + browserTypes: string[], + planLabels: string[], + httpHeaders: string[], rebaselineImages: boolean, setStaticBaseline: boolean, event_time: number, properties: DeploymentProperties, + applicationId?: string, + environmentId?: string, + uri?: string, revision?: string, + mablBranch?: string, ): any { const requestBody: any = {}; @@ -134,15 +157,37 @@ export class MablApiClient { requestBody.application_id = applicationId; } + if (mablBranch) { + requestBody.source_control_tag = mablBranch; + } + const planOverrides: any = {}; - if (browserTypes) { - planOverrides.browser_types = browserTypes.split(','); + if (browserTypes.length) { + planOverrides.browser_types = browserTypes; } + if (uri) { planOverrides.uri = uri; } + + if (httpHeaders.length) { + planOverrides.http_headers = httpHeaders.map((header) => { + const parts = header.split(':', 2); // allow for colon in the header value + return { + name: parts[0], + value: parts[1], + log_header_value: false, + }; + }); + planOverrides.http_headers_required = true; + } + requestBody.plan_overrides = planOverrides; + if (planLabels.length) { + requestBody.plan_labels = planLabels; + } + if (revision) { requestBody.revision = revision; } diff --git a/test/suite.test.ts b/test/suite.test.ts index c53e5dc8..f2883422 100644 --- a/test/suite.test.ts +++ b/test/suite.test.ts @@ -1,13 +1,77 @@ import {MablApiClient} from '../src/mablApiClient'; +import { booleanInput, optionalArrayInput, optionalInput, run } from "../src"; +import { ActionInputs } from '../src/constants'; describe('GitHub Action tests', () => { + // Place the input into ENV var the same as in GitHub Actions + function setGithubInput(name: string, value: string): void { + process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] = value; + } + + function assertExitCode(expected: number): void { + expect(process.exitCode).toEqual(expected); + } + + it('handles invalid application/environment ids', async () => { + setGithubInput(ActionInputs.ApplicationId, ''); + setGithubInput(ActionInputs.EnvironmentId, ''); + await run(); + assertExitCode(1); + }); + + it('parses array inputs', () => { + setGithubInput(ActionInputs.BrowserTypes, ''); + expect(optionalArrayInput(ActionInputs.BrowserTypes)).toEqual([]); + + setGithubInput(ActionInputs.BrowserTypes, 'chrome '); + expect(optionalArrayInput(ActionInputs.BrowserTypes)).toEqual(['chrome']); + + setGithubInput(ActionInputs.BrowserTypes, 'chrome, firefox '); + expect(optionalArrayInput(ActionInputs.BrowserTypes)).toEqual(['chrome', 'firefox']); + + setGithubInput(ActionInputs.BrowserTypes, 'chrome\nfirefox\nsafari '); + expect(optionalArrayInput(ActionInputs.BrowserTypes)).toEqual(['chrome', 'firefox', 'safari']); + }); + + it('parses boolean inputs', () => { + setGithubInput(ActionInputs.RebaselineImages, ''); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(false); + + setGithubInput(ActionInputs.RebaselineImages, 'false '); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(false); + + setGithubInput(ActionInputs.RebaselineImages, 'False '); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(false); + + setGithubInput(ActionInputs.RebaselineImages, 'True '); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(true); + + setGithubInput(ActionInputs.RebaselineImages, 'true '); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(true); + + setGithubInput(ActionInputs.RebaselineImages, 'TRUE'); + expect(booleanInput(ActionInputs.RebaselineImages)).toEqual(true); + }); + + + it('parses optional string inputs', () => { + setGithubInput(ActionInputs.ApplicationId, ''); + expect(optionalInput(ActionInputs.ApplicationId)).toBeUndefined(); + + setGithubInput(ActionInputs.ApplicationId, 'baz '); + expect(optionalInput(ActionInputs.ApplicationId)).toEqual('baz'); + + setGithubInput(ActionInputs.ApplicationId, 'BAZ'); + expect(optionalInput(ActionInputs.ApplicationId)).toEqual('BAZ'); + }); + it('builds the request correctly with all options', () => { const expected = { environment_id: 'env', application_id: 'app', plan_overrides: { - browser_types: ['firefox', ' chrome', ' internet_explorer'], + browser_types: ['firefox', 'chrome', 'internet_explorer'], uri: 'uri', }, actions: {rebaseline_images: true, set_static_baseline: true}, @@ -28,10 +92,9 @@ describe('GitHub Action tests', () => { }; const apiClient = new MablApiClient('test'); const requestBody = apiClient.buildRequestBody( - 'app', - 'env', - 'firefox, chrome, internet_explorer', - 'uri', + ['firefox', 'chrome', 'internet_explorer'], + [], + [], true, true, @@ -49,6 +112,9 @@ describe('GitHub Action tests', () => { repository_pull_request_merged_at: '2019', repository_pull_request_created_at: '2019', }, + 'app', + 'env', + 'uri', 'abcs', ); expect(expected).toStrictEqual(requestBody); @@ -57,7 +123,21 @@ describe('GitHub Action tests', () => { it('builds the request correctly with some options', () => { const expected = { application_id: 'app', - plan_overrides: {uri: 'uri'}, + plan_labels: ['alpha', 'beta'], + plan_overrides: { + uri: 'uri', + browser_types: ['chrome', 'firefox'], + http_headers: [{ + name: 'Header-Uno', + value: 'value-uno', + log_header_value: false, + }, { + name: 'Header-Dos', + value: 'value-dos', + log_header_value: false, + }], + http_headers_required: true + }, actions: {}, revision: 'abcs', properties: { @@ -76,10 +156,10 @@ describe('GitHub Action tests', () => { }; const apiClient = new MablApiClient('test'); const requestBody = apiClient.buildRequestBody( - 'app', - '', - '', - 'uri', + + ['chrome', 'firefox'], + ['alpha', 'beta'], + ['Header-Uno:value-uno', 'Header-Dos:value-dos'], false, false, @@ -97,6 +177,9 @@ describe('GitHub Action tests', () => { repository_pull_request_merged_at: '2019', repository_pull_request_created_at: '2019', }, + 'app', + '', + 'uri', 'abcs', ); expect(expected).toStrictEqual(requestBody);