From 61806dbda29996bb0149f9121bdace46592885e9 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Fri, 23 Feb 2024 13:06:54 -0700 Subject: [PATCH 01/14] ARCH-2011 - Adding additional outputs to accommodate testing +semver:minor --- .gitignore | 5 +-- README.md | 27 ++++++++++----- action.yml | 98 +++++++++++++++++++++++++++++------------------------- 3 files changed, 75 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 43f90b8..35853dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -node_modules/ -/.vscode/launch.json +node_modules/ +/.vscode/launch.json +/pull-request.json diff --git a/README.md b/README.md index d39b56e..9d4325d 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,18 @@ This action does not run the Jest tests itself and it can only process one resul ## Failures -The status check can be seen as a new item on the workflow run, a PR comment or on the PR Status Check section. If the test results contain failures, the status check will be marked as failed. Having the status check marked as failed will prevent PRs from being merged. If this status check behavior is not desired, the `ignore-test-failures` input can be set and the outcome will be marked as neutral if test failures are detected. The status badge that is shown in the comment or status check body will still indicate it was a failure though. +The test status & action's conclusion can be viewed in multiple places: + +- In the body of a PR comment this action generates +- Next to the name of one of the status checks under the `Checks` section of a PR +- Next to the name of one of the status checks under the `Jobs` section of the workflow run +- In the body of a status check listed on the workflow run + +If the test results contain failures, the status check's conclusion will be set to `failure`. If the status check is required and its conclusion is `failure` the PR cannot be merged. If this required status check behavior is not desired, the `ignore-test-failures` input can be set and the conclusion will be marked as `neutral` if test failures are detected. The status badge that is shown in the comment or status check body will still indicate it was a `failure` though. ## Limitations -GitHub does have a size limitation of 65535 characters for a Status Check body or a PR Comment. This action will fail if the test results exceed the GitHub [limit]. To mitigate this size issue only failed tests are included in the output. +GitHub does have a size limitation of 65535 characters for a Status Check body or a PR Comment. This action would fail if the test results exceeded the GitHub [limit]. To mitigate this size issue only details for failed tests are included in the output in addition to a badge, duration info and outcome info. If the comment still exceeds that size, it will be truncated with a note to see the remaining output in the log. If you have multiple workflows triggered by the same `pull_request` or `push` event, GitHub creates one checksuite for that commit. The checksuite gets assigned to one of the workflows randomly and all status checks for that commit are reported to that checksuite. That means if there are multiple workflows with the same trigger, your status checks may show on a different workflow run than the run that created them. @@ -74,9 +81,13 @@ For failed test runs you can expand each failed test and view more details about ## Outputs -| Output | Description | -|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `test-outcome` | Test outcome based on presence of failing tests: *Failed,Passed*
If exceptions are thrown or if it exits early because of argument errors, this is set to Failed. | +| Output | Description | +|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `test-outcome` | Test outcome based on presence of failing tests: *Failed,Passed*
If exceptions are thrown or if it exits early because of argument errors, this is set to Failed. | +| `test-results-truncated` | Flag indicating whether test results were truncated due to markdown exceeding character limit of 65535. | +| `test-results-file-path` | File path for the file that contains the pre-truncated test results in markdown format. This is the same output that is posted in the PR comment. | +| `status-check-ids` | A comma-separated string of IDs for any status checks that were created. This is only set if `create-status-check` is `true` and one or more status checks were created successfully. | +| `pr-comment-id` | The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully. | ## Usage Examples @@ -103,7 +114,7 @@ jobs: - name: Process jest results with default if: always() # You may also reference just the major or major.minor version - uses: im-open/process-jest-test-results@v2.1.3 + uses: im-open/process-jest-test-results@v2.2.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} results-file: 'src/ProjectWithJestTests/jest-results.json @@ -125,7 +136,7 @@ jobs: - name: Process jest results id: process-jest - uses: im-open/process-jest-test-results@v2.1.3 + uses: im-open/process-jest-test-results@v2.2.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} results-file: 'jest.json' @@ -193,7 +204,7 @@ This project has adopted the [im-open's Code of Conduct](https://github.com/im-o ## License -Copyright © 2023, Extend Health, LLC. Code released under the [MIT license](LICENSE). +Copyright © 2024, Extend Health, LLC. Code released under the [MIT license](LICENSE). [Incrementing the Version]: #incrementing-the-version diff --git a/action.yml b/action.yml index a9b388b..5691bc4 100644 --- a/action.yml +++ b/action.yml @@ -1,45 +1,53 @@ -name: process-jest-test-results - -description: | - Action that parses a jest json results file and creates a status check or pr comment with the results. - Tests are not run as part of these action. - The results can be seen on the workflow run or PR. - -inputs: - github-token: - description: 'Token used to interact with the repository. Generally secrets.GITHUB_TOKEN.' - required: true - results-file: - description: 'The json test results file output by jest.' - required: true - report-name: - description: 'The desired name of the report that is shown on the PR Comment and inside the Status Check.' - required: true - default: Jest Test Results - ignore-test-failures: - description: 'When set to true the status check is set to neutral when there are test failures and it will not block pull requests.' - required: false - default: 'false' - create-status-check: - description: 'Flag indicating whether a status check with test results should be generated.' - required: true - default: 'true' - create-pr-comment: - description: 'Flag indicating whether a PR comment with test results should be generated. When `true` the default behavior is to update an existing comment if one exists.' - required: true - default: 'true' - update-comment-if-one-exists: - description: 'When `create-pr-comment` is true, this flag determines whether a new comment is created or if the action updates an existing comment if one is found which is the default behavior.' - required: true - default: 'true' - timezone: - description: 'IANA time zone name (e.g. America/Denver) to display dates in. If timezone is not provided, dates will be shown in UTC.' - required: false - -outputs: - test-outcome: - description: 'Test outcome based on presence of failing tests: Failed|Passed. If exceptions are thrown or if it exits early because of argument errors, this is set to Failed.' - -runs: - using: 'node16' - main: 'dist/index.js' +name: process-jest-test-results + +description: | + Action that parses a jest json results file and creates a status check or pr comment with the results. + Tests are not run as part of these action. + The results can be seen on the workflow run or PR. + +inputs: + github-token: + description: 'Token used to interact with the repository. Generally secrets.GITHUB_TOKEN.' + required: true + results-file: + description: 'The json test results file output by jest.' + required: true + report-name: + description: 'The desired name of the report that is shown on the PR Comment and inside the Status Check.' + required: true + default: Jest Test Results + ignore-test-failures: + description: 'When set to true the status check is set to neutral when there are test failures and it will not block pull requests.' + required: false + default: 'false' + create-status-check: + description: 'Flag indicating whether a status check with test results should be generated.' + required: true + default: 'true' + create-pr-comment: + description: 'Flag indicating whether a PR comment with test results should be generated. When `true` the default behavior is to update an existing comment if one exists.' + required: true + default: 'true' + update-comment-if-one-exists: + description: 'When `create-pr-comment` is true, this flag determines whether a new comment is created or if the action updates an existing comment if one is found which is the default behavior.' + required: true + default: 'true' + timezone: + description: 'IANA time zone name (e.g. America/Denver) to display dates in. If timezone is not provided, dates will be shown in UTC.' + required: false + +outputs: + test-outcome: + description: 'Test outcome based on presence of failing tests: Failed|Passed. If exceptions are thrown or if it exits early because of argument errors, this is set to Failed.' + test-results-truncated: + description: 'Flag indicating whether test results were truncated due to markdown exceeding character limit of 65535.' + test-results-file-path: + description: 'File path for the file that contains the pre-truncated test results in markdown format. This is the same output that is posted in the PR comment.' + status-check-ids: + description: 'A comma-separated string of IDs for any status checks that were created. This is only set if `create-status-check` is `true` and one or more status checks were created successfully.' + pr-comment-id: + description: 'The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully.' + +runs: + using: 'node16' + main: 'dist/index.js' From a6ac98e6e333bf8dfec936f4da299d422cabd1b6 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Fri, 23 Feb 2024 13:09:31 -0700 Subject: [PATCH 02/14] ARCH-2011 - Adding files that will help with testing scenarios --- test/assert-file-contents-match.sh | 58 +++++++++++++++++++ test/assert-pr-comment-exists.js | 34 +++++++++++ .../assert-pr-comment-matches-expectations.js | 57 ++++++++++++++++++ ...ssert-status-check-matches-expectations.js | 44 ++++++++++++++ test/assert-status-checks-exist.js | 42 ++++++++++++++ test/assert-value-is-empty.sh | 32 ++++++++++ test/assert-value-is-not-empty.sh | 32 ++++++++++ test/assert-values-do-not-match.sh | 38 ++++++++++++ test/assert-values-match.sh | 38 ++++++++++++ test/delete-pr-comment.js | 24 ++++++++ 10 files changed, 399 insertions(+) create mode 100755 test/assert-file-contents-match.sh create mode 100644 test/assert-pr-comment-exists.js create mode 100644 test/assert-pr-comment-matches-expectations.js create mode 100644 test/assert-status-check-matches-expectations.js create mode 100644 test/assert-status-checks-exist.js create mode 100755 test/assert-value-is-empty.sh create mode 100755 test/assert-value-is-not-empty.sh create mode 100755 test/assert-values-do-not-match.sh create mode 100755 test/assert-values-match.sh create mode 100644 test/delete-pr-comment.js diff --git a/test/assert-file-contents-match.sh b/test/assert-file-contents-match.sh new file mode 100755 index 0000000..cb4c192 --- /dev/null +++ b/test/assert-file-contents-match.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +name='' +expectedFileName='' +actualFileName='' + +for arg in "$@"; do + case $arg in + --name) + name=$2 + shift # Remove argument --name from `$@` + shift # Remove argument value from `$@` + ;; + --expectedFileName) + expectedFileName=$2 + shift # Remove argument --expected from `$@` + shift # Remove argument value from `$@` + ;; + --actualFileName) + actualFileName=$2 + shift # Remove argument --actual from `$@` + shift # Remove argument value from `$@` + ;; + + esac +done + +echo " +Asserting file contents match: +Expected file name: '$expectedFileName' +Actual file name: '$actualFileName'" + +# First make sure the actual file exists +if [ -f "$actualFileName" ] +then + echo " +$actualFileName exists which is expected." + actualFileContents=$(cat $actualFileName) +else + echo " +$actualFileName does not exist which is not expected" + exit 1 +fi +expectedFileContents=$(cat $expectedFileName) + + +# Then compare the contents +name="file contents" +echo " +Expected $name: '$expectedFileContents' +Actual $name: '$actualFileContents'" + +if [ "$expectedFileContents" != "$actualFileContents" ]; then + echo "The expected $name does not match the actual $name." + exit 1 +else + echo "The expected and actual $name values match." +fi \ No newline at end of file diff --git a/test/assert-pr-comment-exists.js b/test/assert-pr-comment-exists.js new file mode 100644 index 0000000..d15614b --- /dev/null +++ b/test/assert-pr-comment-exists.js @@ -0,0 +1,34 @@ +module.exports = async (github, core, commentId) => { + core.info(`\nAsserting that PR Comment with the following id exists: '${commentId}'`); + + let actualComment; + + if (!commentId || commentId.trim() === '') { + core.setFailed(`The comment id provided was empty.`); + } + + const commentResponse = await github.rest.issues.getComment({ + owner: 'im-open', + repo: 'process-jest-test-results', + comment_id: commentId.trim() + }); + + if (!commentResponse && !commentResponse.data) { + core.setFailed(`Comment ${commentId} does not appear to exist.`); + } else { + core.info(`Comment ${commentId} exists.`); + let rawComment = commentResponse.data; + + actualComment = { + id: rawComment.id, + body: rawComment.body, + createdAt: rawComment.created_at, + updatedAt: rawComment.updated_at, + issueUrl: rawComment.issue_url + }; + core.info(`Comment ${actualComment.id} details:`); + console.log(actualComment); + } + + return actualComment; +}; diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js new file mode 100644 index 0000000..886c603 --- /dev/null +++ b/test/assert-pr-comment-matches-expectations.js @@ -0,0 +1,57 @@ +module.exports = async (core, comment, expectedValues) => { + function assertCreatedAndUpdatedMatch(created, updated) { + core.info(`\n\tCreated: '${created}'`); + core.info(`\tUpdated: '${updated}'`); + + if (created != updated) { + core.setFailed(`\tThe created and updated dates should match, which is NOT expected.`); + } else { + core.info(`\tThe created and updated dates match, which is expected.`); + } + } + + function assertUpdatedIsAfterCreated(created, updated) { + core.info(`\n\tCreated: '${created}'`); + core.info(`\tUpdated: '${updated}'`); + + if (created >= updated) { + core.setFailed(`\tThe created date is on or after the updated date, which is NOT expected.`); + } else { + core.info(`\tThe created date is before the updated date, which is expected.`); + } + } + + function assertValueContainsSubstring(variableName, value, substring) { + core.startGroup(`\n\tChecking ${variableName} contains the substring.`); + if (value.includes(substring)) { + core.info(`\tThe ${variableName} string contains the substring.`); + } else { + core.setFailed(`\tThe ${variableName} string does not contain the substring.`); + core.info(`\n\tExpected ${variableName}: '${value}'`); + core.info(`\tActual ${variableName}: '${substring}'`); + } + core.endGroup(); + } + + function validateProps() { + core.info(`\nAsserting that PR Comment properties match the expected values.`); + core.info(`Comment ID: ${comment.id}`); + + assertValueContainsSubstring('Body', expectedValues['prefixAndBody'], comment.body); + + switch (expectedValues.action) { + case 'updated': + assertUpdatedIsAfterCreated(comment.createdAt, comment.updatedAt); + break; + case 'created': + assertCreatedAndUpdatedMatch(comment.createdAt, comment.updatedAt); + break; + default: + core.setFailed(`The action '${expectedValues.action}' is not supported.`); + break; + } + } + + validateProps(); + await new Promise(r => setTimeout(r, 5 * 1000)); +}; diff --git a/test/assert-status-check-matches-expectations.js b/test/assert-status-check-matches-expectations.js new file mode 100644 index 0000000..7a1678c --- /dev/null +++ b/test/assert-status-check-matches-expectations.js @@ -0,0 +1,44 @@ +module.exports = async (core, statusCheck, expectedValues) => { + function assertValuesMatch(variableName, expectedValue, actualValue) { + core.info(`\n\tExpected ${variableName}: '${expectedValue}'`); + core.info(`\tActual ${variableName}: '${actualValue}'`); + + if (expectedValue != actualValue) { + core.setFailed(`\tThe expected ${variableName} does not match the actual ${variableName}.`); + } else { + core.info(`\tThe expected and actual ${variableName} values match.`); + } + } + + function assertValueContainsSubstring(variableName, value, substring) { + core.startGroup(`\tChecking ${variableName} contains the substring.`); + if (value.includes(substring)) { + core.info(`\tThe ${variableName} string contains the substring.`); + } else { + core.setFailed(`\tThe ${variableName} string does not contain the substring.`); + core.info(`\n\tExpected ${variableName}: '${value}'`); + core.info(`\tActual ${variableName}: '${substring}'`); + } + core.endGroup(); + } + + function validateProps() { + core.info(`\nAsserting that Status Check properties match the expected values.`); + core.info(`Status Check: ${statusCheck.id}`); + + assertValuesMatch('Name', expectedValues['name'], statusCheck.name); + assertValuesMatch('Status', expectedValues['status'], statusCheck.status); + assertValuesMatch('Conclusion', expectedValues['conclusion'], statusCheck.conclusion); + assertValuesMatch('Title', expectedValues['title'], statusCheck.title); + + // The summary should be something like: 'This test run completed at `Wed, 21 Feb 2024 20:21:48 GMT`' + // so just check that it contains the static portion. + assertValueContainsSubstring('Summary', statusCheck.summary, 'This test run completed at `'); + + // The text will be a just the markdown for a single trx file. Check that the expected text + // (which is the markdown for all trx files) contains the subset. + assertValueContainsSubstring('Text', expectedValues['text'], statusCheck.text); + } + + validateProps(); +}; diff --git a/test/assert-status-checks-exist.js b/test/assert-status-checks-exist.js new file mode 100644 index 0000000..b22581b --- /dev/null +++ b/test/assert-status-checks-exist.js @@ -0,0 +1,42 @@ +module.exports = async (github, core, statusCheckIds) => { + core.info(`\nAsserting that checks with the following ids exist: '${statusCheckIds}'`); + + const actualChecks = []; + const checkIds = statusCheckIds.split(','); + for (const checkId of checkIds) { + if (!checkId || checkId.trim() === '') { + continue; + } + + core.startGroup(`Checking for the existence of status check ${checkId}.`); + const checkResponse = await github.rest.checks.get({ + owner: 'im-open', + repo: 'process-jest-test-results', + check_run_id: checkId.trim() + }); + if (!checkResponse && !checkResponse.data) { + core.setFailed(`Status Check ${checkId} does not appear to exist.`); + } else { + core.info(`Status Check ${checkId} exists.`); + let rawCheck = checkResponse.data; + + const check = { + id: rawCheck.id, + name: rawCheck.name, + status: rawCheck.status, + conclusion: rawCheck.conclusion, + startedAt: rawCheck.started_at, + completedAt: rawCheck.completed_at, + title: rawCheck.output.title, + summary: rawCheck.output.summary, + prNumber: rawCheck.pull_requests.length > 0 ? rawCheck.pull_requests[0].number : null, + text: rawCheck.output.text + }; + core.info(`Check ${check.id} details:`); + console.log(check); + actualChecks.push(check); + } + core.endGroup(); + } + return actualChecks; +}; diff --git a/test/assert-value-is-empty.sh b/test/assert-value-is-empty.sh new file mode 100755 index 0000000..ae9a305 --- /dev/null +++ b/test/assert-value-is-empty.sh @@ -0,0 +1,32 @@ +#!/bin/bash + + +name='' +value='' + +for arg in "$@"; do + case $arg in + --name) + name=$2 + shift # Remove argument --name from `$@` + shift # Remove argument value from `$@` + ;; + --value) + value=$2 + shift # Remove argument --expected from `$@` + shift # Remove argument value from `$@` + ;; + esac +done + +echo " +Asserting $name is empty +$name value: '$value'" + +if [ -z "$value" ] +then + echo "$name is empty which is expected." +else + echo "$name is not empty which is not expected." + exit 1 +fi \ No newline at end of file diff --git a/test/assert-value-is-not-empty.sh b/test/assert-value-is-not-empty.sh new file mode 100755 index 0000000..cdf06b1 --- /dev/null +++ b/test/assert-value-is-not-empty.sh @@ -0,0 +1,32 @@ +#!/bin/bash + + +name='' +value='' + +for arg in "$@"; do + case $arg in + --name) + name=$2 + shift # Remove argument --name from `$@` + shift # Remove argument value from `$@` + ;; + --value) + value=$2 + shift # Remove argument --expected from `$@` + shift # Remove argument value from `$@` + ;; + esac +done + +echo " +Asserting $name is not empty +$name value: '$value'" + +if [ -z "$value" ] +then + echo "$name is empty which is not expected." + exit 1 +else + echo "$name is not empty which is expected." +fi \ No newline at end of file diff --git a/test/assert-values-do-not-match.sh b/test/assert-values-do-not-match.sh new file mode 100755 index 0000000..b8371fe --- /dev/null +++ b/test/assert-values-do-not-match.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +name='' +value1='' +value2='' + +for arg in "$@"; do + case $arg in + --name) + name=$2 + shift # Remove argument --name from `$@` + shift # Remove argument value from `$@` + ;; + --value1) + value1=$2 + shift # Remove argument --expected from `$@` + shift # Remove argument value from `$@` + ;; + --value2) + value2=$2 + shift # Remove argument --actual from `$@` + shift # Remove argument value from `$@` + ;; + + esac +done + +echo " +Asserting $name values do not match +$name 1: '$value1' +$name 2: '$value2'" + +if [ "$value1" != "$value2" ]; then + echo "$name 1 does not match $name 2, which is expected." +else + echo "Values 1 and 2 match, which is not expected." + exit 1 +fi \ No newline at end of file diff --git a/test/assert-values-match.sh b/test/assert-values-match.sh new file mode 100755 index 0000000..c3881dd --- /dev/null +++ b/test/assert-values-match.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +name='' +expectedValue='' +actualValue='' + +for arg in "$@"; do + case $arg in + --name) + name=$2 + shift # Remove argument --name from `$@` + shift # Remove argument value from `$@` + ;; + --expected) + expectedValue=$2 + shift # Remove argument --expected from `$@` + shift # Remove argument value from `$@` + ;; + --actual) + actualValue=$2 + shift # Remove argument --actual from `$@` + shift # Remove argument value from `$@` + ;; + + esac +done + +echo " +Asserting $name values match +Expected $name: '$expectedValue' +Actual $name: '$actualValue'" + +if [ "$expectedValue" != "$actualValue" ]; then + echo "The expected $name does not match the actual $name." + exit 1 +else + echo "The expected and actual $name values match." +fi \ No newline at end of file diff --git a/test/delete-pr-comment.js b/test/delete-pr-comment.js new file mode 100644 index 0000000..4cbe121 --- /dev/null +++ b/test/delete-pr-comment.js @@ -0,0 +1,24 @@ +module.exports = async (github, core, commentId) => { + core.info(`\nDeleting comment '${commentId}'`); + + if (!commentId) { + core.setFailed(`The comment id provided was empty.`); + } + + await github + .request(`DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}`, { + owner: 'im-open', + repo: 'process-jest-test-results', + comment_id: commentId, + headers: { + 'X-GitHub-Api-Version': '2022-11-28' + } + }) + .then(() => { + core.info(`The comment '${commentId}' was deleted successfully.`); + }) + .catch(error => { + core.info(`An error occurred deleting comment '${commentId}'. Error: ${error.message}`); + core.info(`You may need to manually clean up the PR comments.`); + }); +}; From 6ce240d55b6b2f1a379c939bdd6f44a4e7ff33fb Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Fri, 23 Feb 2024 15:36:56 -0700 Subject: [PATCH 03/14] ARCH-2011 - Adding the unit tests --- .github/workflows/build-and-review-pr.yml | 290 ++++++++++++++++++ dist/index.js | 206 +++++++------ src/main.js | 18 +- src/markup.js | 171 +++++------ src/utils.js | 24 +- test/files/empty-results.json | 0 .../expected-results-for-failing-tests.md | 79 +++++ test/files/expected-results-for-no-tests.md | 37 +++ .../expected-results-for-passing-tests.md | 49 +++ test/files/failing.json | 131 ++++++++ test/files/no-tests.json | 33 ++ test/files/passing.json | 122 ++++++++ 12 files changed, 973 insertions(+), 187 deletions(-) create mode 100644 test/files/empty-results.json create mode 100644 test/files/expected-results-for-failing-tests.md create mode 100644 test/files/expected-results-for-no-tests.md create mode 100644 test/files/expected-results-for-passing-tests.md create mode 100644 test/files/failing.json create mode 100644 test/files/no-tests.json create mode 100644 test/files/passing.json diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index 67e987c..5a25d82 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -60,3 +60,293 @@ jobs: # The npm script to run to build the action. This is typically 'npm run build' if the # action needs to be compiled. For composite-run-steps actions this is typically empty. build-command: 'npm run build' + + unit-tests: + runs-on: ubuntu-latest + env: + FAILING_MD_FILE: './test/files/expected-results-for-failing-tests.md' + PASSING_MD_FILE: './test/files/expected-results-for-passing-tests.md' + NO_TESTS_MD_FILE: './test/files/expected-results-for-no-tests.md' + + steps: + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' SETUP ' + run: echo "" + + - name: Setup - Checkout the action + uses: actions/checkout@v4 + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 1 - MISSING TOKEN INPUT ' + run: echo "" + + - name: 1 - When process-jest-test-results is called with a missing github-token input + id: missing-github-token + if: always() + continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed. + uses: ./ + with: + github-token: '' + results-file: './test/files/empty-results.json' + + - name: 1 - Then the action outcome should be failure + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-github-token.outcome }}" + + - name: 1 - And each of the outputs should be empty + if: always() + run: | + ./test/assert-value-is-empty.sh --name "test-outcome output" --value "${{ steps.missing-github-token.outputs.test-outcome }}" + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.missing-github-token.outputs.test-results-truncated }}" + ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.missing-github-token.outputs.test-results-file-path }}" + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.missing-github-token.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-github-token.outputs.pr-comment-id }}" + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 2 - MISSING RESULTS_FILE INPUT ' + run: echo "" + + - name: 2 - When process-jest-test-results is called with a missing results-file input + id: missing-results-file + if: always() + continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed. + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: '' + + - name: 2 - Then the action outcome should be failure + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-results-file.outcome }}" + + - name: 2 - And each of the outputs should be empty + if: always() + run: | + ./test/assert-value-is-empty.sh --name "test-outcome output" --value "${{ steps.missing-results-file.outputs.test-outcome }}" + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.missing-results-file.outputs.test-results-truncated }}" + ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.missing-results-file.outputs.test-results-file-path }}" + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.missing-results-file.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-results-file.outputs.pr-comment-id }}" + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 3 - RESULTS_FILE DOES NOT EXIST ' + run: echo "" + + - name: 3 - When process-jest-test-results is called with a results file that does not exist + id: file-does-not-exist + if: always() + continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed. + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: './test/files/file-that-does-not-exist.json' + create-status-check: false + create-pr-comment: false + + - name: 3 - Then the action outcome should be failure + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.file-does-not-exist.outcome }}" + + - name: 3 - And the 'test-outcome' output should be Failed + if: always() + run: | + ./test/assert-values-match.sh --name "test-outcome output" --expected 'Failed' --actual "${{ steps.file-does-not-exist.outputs.test-outcome }}" + + - name: 3 - And the remaining outputs should be empty + if: always() + run: | + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.file-does-not-exist.outputs.test-results-truncated }}" + ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.file-does-not-exist.outputs.test-results-file-path }}" + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.file-does-not-exist.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.file-does-not-exist.outputs.pr-comment-id }}" + + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 4 - RESULTS_FILE IS EMPTY ' + run: echo "" + + - name: 4 - When process-jest-test-results is called with a results file that is empty + id: empty-file + if: always() + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: './test/files/empty-results.json' + create-status-check: false + create-pr-comment: false + + - name: 4 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.empty-file.outcome }}" + + - name: 4 - And the 'test-outcome' output should be Failed + if: always() + run: | + ./test/assert-values-match.sh --name "test-outcome output" --expected 'Failed' --actual "${{ steps.empty-file.outputs.test-outcome }}" + + - name: 4 - And the remaining outputs should be empty + if: always() + run: | + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.empty-file.outputs.test-results-truncated }}" + ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.empty-file.outputs.test-results-file-path }}" + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.empty-file.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.empty-file.outputs.pr-comment-id }}" + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 5 - PASSING TESTS ' + run: echo "" + + - name: 5 - When process-jest-test-results is called with a results file that has all passing tests + id: passing-tests + if: always() + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: './test/files/passing.json' + create-status-check: false + create-pr-comment: false + timezone: 'America/Denver' + report-name: 'Passing Test Results' + + - name: 5 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.passing-tests.outcome }}" + + - name: 5 - And the 'test-outcome' output should be Passed + if: always() + run: | + ./test/assert-values-match.sh --name "test-outcome output" --expected 'Passed' --actual "${{ steps.passing-tests.outputs.test-outcome }}" + + - name: 5 - And the 'test-results-file-path output' should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.passing-tests.outputs.test-results-file-path }}" + + - name: 5 - And the remaining outputs should be empty since status checks and pr comments were not created + if: always() + run: | + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.passing-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.passing-tests.outputs.pr-comment-id }}" + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.passing-tests.outputs.test-results-truncated }}" + + - name: 5 - And the contents of test-results.md file should match the contents of ${{ env.PASSING_MD_FILE }} file + if: always() + run: | + # Comparing the test-results.md file will ensure that: + # - The provided timezone (MST/MDT) is used + # - The provided report name is used + # - The badge has the right count/status/color + # - The Duration stats are included in the report + # - The Counter stats are included in the report + + expectedFileName="${{ env.PASSING_MD_FILE }}" + actualFileName="${{ steps.passing-tests.outputs.test-results-file-path }}" + ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 6 - FAILING TESTS ' + run: echo "" + + - name: 6 - When process-jest-test-results is called with a results file that has failing tests + id: failing-tests + if: always() + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: './test/files/failing.json' + create-status-check: false + create-pr-comment: false + # timezone: 'UTC' # Test the default + # report-name: 'Jest Test Results' # Test the default + + - name: 6 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.failing-tests.outcome }}" + + - name: 6 - And the 'test-outcome' output should be Failed + if: always() + run: | + ./test/assert-values-match.sh --name "test-outcome output" --expected 'Failed' --actual "${{ steps.failing-tests.outputs.test-outcome }}" + + - name: 6 - And the 'test-results-file-path output' should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.failing-tests.outputs.test-results-file-path }}" + + - name: 6 - And the remaining outputs should be empty since status checks and pr comments were not created + if: always() + run: | + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.failing-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.failing-tests.outputs.pr-comment-id }}" + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.failing-tests.outputs.test-results-truncated }}" + + - name: 6 - And the contents of test-results.md file should match the contents of ${{ env.FAILING_MD_FILE }} file + if: always() + run: | + # Comparing the test-results.md file will ensure that: + # - The default timezone (UTC) is used + # - The default report name (Jest Test Results) is used + # - The badge has the right count/status/color + # - The Duration stats are included in the report + # - The Counter stats are included in the report + # - The failing test details are included in the report + + expectedFileName="${{ env.FAILING_MD_FILE }}" + actualFileName="${{ steps.failing-tests.outputs.test-results-file-path }}" + ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 7 - NO TESTS REPORTED ' + run: echo "" + + - name: 7 - When process-jest-test-results is called with a results file that has no tests reported + id: no-tests + if: always() + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: './test/files/no-tests.json' + report-name: 'Missing Test Results' + create-status-check: false + create-pr-comment: false + + - name: 7 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.no-tests.outcome }}" + + - name: 7 - And the 'test-outcome' output should be Passed + if: always() + run: | + ./test/assert-values-match.sh --name "test-outcome output" --expected 'Passed' --actual "${{ steps.no-tests.outputs.test-outcome }}" + + - name: 7 - And the 'test-results-file-path output' should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.no-tests.outputs.test-results-file-path }}" + + - name: 7 - And the remaining outputs should be empty since status checks and pr comments were not created + if: always() + run: | + ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.no-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.no-tests.outputs.pr-comment-id }}" + ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.no-tests.outputs.test-results-truncated }}" + + - name: 7 - And the contents of test-results.md file should match the contents of ${{ env.NO_TESTS_MD_FILE }} file + if: always() + run: | + # Comparing the test-results.md file will ensure that: + # - The default timezone (UTC) is used + # - The default report name (Missing Test Results) is used + # - The badge has the right count/status/color + # - The Duration section should not be included in the report + # - The Counter stats are included in the report + # - The no-test details are included in the report + + expectedFileName="${{ env.NO_TESTS_MD_FILE }}" + actualFileName="${{ steps.no-tests.outputs.test-results-file-path }}" + ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName diff --git a/dist/index.js b/dist/index.js index 33a056f..56c82a8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2369,6 +2369,7 @@ var require_utils2 = __commonJS({ 'src/utils.js'(exports2, module2) { var core2 = require_core(); var fs = require('fs'); + var path = require('path'); async function readJsonResultsFromFile2(resultsFile2) { core2.info('Reading results from jest results file....'); if (fs.existsSync(resultsFile2)) { @@ -2396,9 +2397,28 @@ var require_utils2 = __commonJS({ core2.info(`There are no failing tests.`); return false; } + function createResultsFile2(results) { + const jobId = process.env.GITHUB_JOB || ''; + const stepId = process.env.GITHUB_ACTION || ''; + const resultsFileName = `test-results-${jobId}-${stepId}.md`; + core2.info(` +Writing results to ${resultsFileName}`); + let resultsFilePath = null; + fs.writeFile(resultsFileName, results, err => { + if (err) { + core2.info(`Error writing results to file. Error: ${err}`); + } else { + core2.info('Successfully created results file.'); + core2.info(`File: ${resultsFileName}`); + } + }); + resultsFilePath = path.resolve(resultsFileName); + return resultsFilePath; + } module2.exports = { readJsonResultsFromFile: readJsonResultsFromFile2, - areThereAnyFailingTests: areThereAnyFailingTests2 + areThereAnyFailingTests: areThereAnyFailingTests2, + createResultsFile: createResultsFile2 }; } }); @@ -19599,13 +19619,12 @@ var require_markup = __commonJS({ var { format, utcToZonedTime } = require_date_fns_tz(); var timezone = core2.getInput('timezone') || 'Etc/UTC'; function getMarkupForJson2(results, reportName2) { - return ` - # ${reportName2} - ${getBadge(results)} - ${getTestTimes(results)} - ${getTestCounters(results)} - ${getTestResultsMarkup(results)} - `; + return `# ${reportName2} + +${getBadge(results)} +${getTestTimes(results)} +${getTestCounters(results)} +${getFailedAndEmptyTestResultsMarkup(results)}`; } function getBadge(results) { const failedCount = results.numFailedTests; @@ -19625,6 +19644,10 @@ var require_markup = __commonJS({ } } function getTestTimes(results) { + let hasTests = results.testResults && results.testResults.length > 0; + if (!hasTests) { + return ''; + } let startSeconds = results.startTime; let endSeconds = results.testResults .map(m => m.endTime) @@ -19634,25 +19657,23 @@ var require_markup = __commonJS({ const duration = (endSeconds - startSeconds) / 1e3; let startDate = new Date(startSeconds); let endDate = new Date(endSeconds); - return ` -
- Duration: ${duration} seconds - - - - - - - - - - - - - -
Start:${formatDate(startDate)}
Finish:${formatDate(endDate)}
Duration:${duration} seconds
-
- `; + return `
+ Duration: ${duration} seconds + + + + + + + + + + + + + +
Start:${formatDate(startDate)}
Finish:${formatDate(endDate)}
Duration:${duration} seconds
+
`; } function getTestCounters(results) { let extraProps = getTableRowIfHasValue('Pending Test Suites:', results.numPendingTestSuites); @@ -19660,38 +19681,35 @@ var require_markup = __commonJS({ extraProps += getTableRowIfHasValue('Runtime Error Test Suites:', results.numRuntimeErrorTestSuites); extraProps += getTableRowIfHasValue('TODO Tests:', results.numTodoTests); let outcome = results.success ? 'Passed' : 'Failed'; - return ` -
- Outcome: ${outcome} | Total Tests: ${results.numTotalTests} | Passed: ${results.numPassedTests} | Failed: ${results.numFailedTests} - - - - - - - - - - - - - - - - - - - - - - - - - ${extraProps} -
Total Test Suites:${results.numTotalTestSuites}
Total Tests:${results.numTotalTests}
Failed Test Suites:${results.numFailedTestSuites}
Failed Tests:${results.numFailedTests}
Passed Test Suites:${results.numPassedTestSuites}
Passed Tests:${results.numPassedTests}
-
- - `; + return `
+ Outcome: ${outcome} | Total Tests: ${results.numTotalTests} | Passed: ${results.numPassedTests} | Failed: ${results.numFailedTests} + + + + + + + + + + + + + + + + + + + + + + + + + ${extraProps} +
Total Test Suites:${results.numTotalTestSuites}
Total Tests:${results.numTotalTests}
Failed Test Suites:${results.numFailedTestSuites}
Failed Tests:${results.numFailedTests}
Passed Test Suites:${results.numPassedTestSuites}
Passed Tests:${results.numPassedTests}
+
`; } function getTableRowIfHasValue(heading, data) { if (data > 0) { @@ -19703,7 +19721,7 @@ var require_markup = __commonJS({ } return ''; } - function getTestResultsMarkup(results, reportName2) { + function getFailedAndEmptyTestResultsMarkup(results, reportName2) { let resultsMarkup = ''; if (!results.testResults || results.testResults.length === 0) { return getNoResultsMarkup(reportName2); @@ -19715,43 +19733,43 @@ var require_markup = __commonJS({ failedTests.forEach(failedTest => { resultsMarkup += getFailedTestMarkup(failedTest); }); - return resultsMarkup.trim(); + return resultsMarkup; } } function getNoResultsMarkup(reportName2) { const testResultIcon = ':grey_question:'; const resultsMarkup = ` - ## ${testResultIcon} ${reportName2} - There were no test results to report. - `; +## ${testResultIcon} ${reportName2} + +There were no test results to report. +`; return resultsMarkup; } function getFailedTestMarkup(failedTest) { core2.debug(`Processing ${failedTest.fullName}`); let failedMsg = failedTest.failureMessages.join('\n').replace(/\u001b\[\d{1,2}m/gi, ''); - return ` -
- :x: ${failedTest.fullName} - - - - - - - - - - - - - - - - - -
Title:${failedTest.title}
Status:${failedTest.status}
Location:${failedTest.location}
Failure Messages:
${failedMsg}
-
- `.trim(); + return `
+ :x: ${failedTest.fullName} + + + + + + + + + + + + + + + + + +
Title:${failedTest.title}
Status:${failedTest.status}
Location:${failedTest.location}
Failure Messages:
${failedMsg}
+
+`; } module2.exports = { getMarkupForJson: getMarkupForJson2 @@ -19761,7 +19779,7 @@ var require_markup = __commonJS({ // src/main.js var core = require_core(); -var { readJsonResultsFromFile, areThereAnyFailingTests } = require_utils2(); +var { readJsonResultsFromFile, areThereAnyFailingTests, createResultsFile } = require_utils2(); var { createStatusCheck, createPrComment } = require_github2(); var { getMarkupForJson } = require_markup(); var requiredArgOptions = { @@ -19783,18 +19801,20 @@ async function run() { return; } const failingTestsFound = areThereAnyFailingTests(resultsJson); + core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); const markupData = getMarkupForJson(resultsJson, reportName); - let conclusion = 'success'; - if (!resultsJson.success) { - conclusion = ignoreTestFailures ? 'neutral' : 'failure'; - } + const resultsFilePath = createResultsFile(markupData); + core.setOutput('test-results-file-path', resultsFilePath); if (shouldCreateStatusCheck) { + let conclusion = 'success'; + if (!resultsJson.success) { + conclusion = ignoreTestFailures ? 'neutral' : 'failure'; + } await createStatusCheck(token, markupData, conclusion, reportName); } if (shouldCreatePRComment) { await createPrComment(token, markupData, updateCommentIfOneExists); } - core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); } catch (error) { if (error instanceof RangeError) { core.info(error.message); diff --git a/src/main.js b/src/main.js index ae09313..92cdabe 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,5 @@ const core = require('@actions/core'); -const { readJsonResultsFromFile, areThereAnyFailingTests } = require('./utils'); +const { readJsonResultsFromFile, areThereAnyFailingTests, createResultsFile } = require('./utils'); const { createStatusCheck, createPrComment } = require('./github'); const { getMarkupForJson } = require('./markup'); @@ -10,6 +10,7 @@ const requiredArgOptions = { const token = core.getInput('github-token', requiredArgOptions); const resultsFile = core.getInput('results-file', requiredArgOptions); + const ignoreTestFailures = core.getBooleanInput('ignore-test-failures'); const shouldCreateStatusCheck = core.getBooleanInput('create-status-check'); const shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); @@ -25,22 +26,25 @@ async function run() { } const failingTestsFound = areThereAnyFailingTests(resultsJson); + core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); const markupData = getMarkupForJson(resultsJson, reportName); - let conclusion = 'success'; - if (!resultsJson.success) { - conclusion = ignoreTestFailures ? 'neutral' : 'failure'; - } + // Create this automatically to facilitate testing + const resultsFilePath = createResultsFile(markupData); + core.setOutput('test-results-file-path', resultsFilePath); if (shouldCreateStatusCheck) { + let conclusion = 'success'; + if (!resultsJson.success) { + conclusion = ignoreTestFailures ? 'neutral' : 'failure'; + } await createStatusCheck(token, markupData, conclusion, reportName); } + if (shouldCreatePRComment) { await createPrComment(token, markupData, updateCommentIfOneExists); } - - core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); } catch (error) { if (error instanceof RangeError) { core.info(error.message); diff --git a/src/markup.js b/src/markup.js index 95cca2f..66a775d 100644 --- a/src/markup.js +++ b/src/markup.js @@ -3,13 +3,12 @@ const { format, utcToZonedTime } = require('date-fns-tz'); const timezone = core.getInput('timezone') || 'Etc/UTC'; function getMarkupForJson(results, reportName) { - return ` - # ${reportName} - ${getBadge(results)} - ${getTestTimes(results)} - ${getTestCounters(results)} - ${getTestResultsMarkup(results)} - `; + return `# ${reportName} + +${getBadge(results)} +${getTestTimes(results)} +${getTestCounters(results)} +${getFailedAndEmptyTestResultsMarkup(results)}`; } function getBadge(results) { @@ -34,6 +33,11 @@ function formatDate(dateToFormat) { } function getTestTimes(results) { + let hasTests = results.testResults && results.testResults.length > 0; + if (!hasTests) { + return ''; + } + let startSeconds = results.startTime; let endSeconds = results.testResults .map(m => m.endTime) @@ -45,25 +49,23 @@ function getTestTimes(results) { let startDate = new Date(startSeconds); let endDate = new Date(endSeconds); - return ` -
- Duration: ${duration} seconds - - - - - - - - - - - - - -
Start:${formatDate(startDate)}
Finish:${formatDate(endDate)}
Duration:${duration} seconds
-
- `; + return `
+ Duration: ${duration} seconds + + + + + + + + + + + + + +
Start:${formatDate(startDate)}
Finish:${formatDate(endDate)}
Duration:${duration} seconds
+
`; } function getTestCounters(results) { @@ -72,38 +74,35 @@ function getTestCounters(results) { extraProps += getTableRowIfHasValue('Runtime Error Test Suites:', results.numRuntimeErrorTestSuites); extraProps += getTableRowIfHasValue('TODO Tests:', results.numTodoTests); let outcome = results.success ? 'Passed' : 'Failed'; - return ` -
- Outcome: ${outcome} | Total Tests: ${results.numTotalTests} | Passed: ${results.numPassedTests} | Failed: ${results.numFailedTests} - - - - - - - - - - - - - - - - - - - - - - - - - ${extraProps} -
Total Test Suites:${results.numTotalTestSuites}
Total Tests:${results.numTotalTests}
Failed Test Suites:${results.numFailedTestSuites}
Failed Tests:${results.numFailedTests}
Passed Test Suites:${results.numPassedTestSuites}
Passed Tests:${results.numPassedTests}
-
- - `; + return `
+ Outcome: ${outcome} | Total Tests: ${results.numTotalTests} | Passed: ${results.numPassedTests} | Failed: ${results.numFailedTests} + + + + + + + + + + + + + + + + + + + + + + + + + ${extraProps} +
Total Test Suites:${results.numTotalTestSuites}
Total Tests:${results.numTotalTests}
Failed Test Suites:${results.numFailedTestSuites}
Failed Tests:${results.numFailedTests}
Passed Test Suites:${results.numPassedTestSuites}
Passed Tests:${results.numPassedTests}
+
`; } function getTableRowIfHasValue(heading, data) { @@ -117,7 +116,7 @@ function getTableRowIfHasValue(heading, data) { return ''; } -function getTestResultsMarkup(results, reportName) { +function getFailedAndEmptyTestResultsMarkup(results, reportName) { let resultsMarkup = ''; if (!results.testResults || results.testResults.length === 0) { @@ -130,16 +129,17 @@ function getTestResultsMarkup(results, reportName) { failedTests.forEach(failedTest => { resultsMarkup += getFailedTestMarkup(failedTest); }); - return resultsMarkup.trim(); + return resultsMarkup; } } function getNoResultsMarkup(reportName) { const testResultIcon = ':grey_question:'; const resultsMarkup = ` - ## ${testResultIcon} ${reportName} - There were no test results to report. - `; +## ${testResultIcon} ${reportName} + +There were no test results to report. +`; return resultsMarkup; } @@ -148,29 +148,28 @@ function getFailedTestMarkup(failedTest) { //Replace an escaped unicode "escape character". It doesn't show correctly in markdown. let failedMsg = failedTest.failureMessages.join('\n').replace(/\u001b\[\d{1,2}m/gi, ''); - return ` -
- :x: ${failedTest.fullName} - - - - - - - - - - - - - - - - - -
Title:${failedTest.title}
Status:${failedTest.status}
Location:${failedTest.location}
Failure Messages:
${failedMsg}
-
- `.trim(); + return `
+ :x: ${failedTest.fullName} + + + + + + + + + + + + + + + + + +
Title:${failedTest.title}
Status:${failedTest.status}
Location:${failedTest.location}
Failure Messages:
${failedMsg}
+
+`; } module.exports = { diff --git a/src/utils.js b/src/utils.js index 35fc1ee..088374c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,6 @@ const core = require('@actions/core'); const fs = require('fs'); +const path = require('path'); async function readJsonResultsFromFile(resultsFile) { core.info('Reading results from jest results file....'); @@ -30,7 +31,28 @@ function areThereAnyFailingTests(json) { return false; } +function createResultsFile(results) { + const jobId = process.env.GITHUB_JOB || ''; + const stepId = process.env.GITHUB_ACTION || ''; + const resultsFileName = `test-results-${jobId}-${stepId}.md`; + + core.info(`\nWriting results to ${resultsFileName}`); + let resultsFilePath = null; + + fs.writeFile(resultsFileName, results, err => { + if (err) { + core.info(`Error writing results to file. Error: ${err}`); + } else { + core.info('Successfully created results file.'); + core.info(`File: ${resultsFileName}`); + } + }); + resultsFilePath = path.resolve(resultsFileName); + return resultsFilePath; +} + module.exports = { readJsonResultsFromFile, - areThereAnyFailingTests + areThereAnyFailingTests, + createResultsFile }; diff --git a/test/files/empty-results.json b/test/files/empty-results.json new file mode 100644 index 0000000..e69de29 diff --git a/test/files/expected-results-for-failing-tests.md b/test/files/expected-results-for-failing-tests.md new file mode 100644 index 0000000..59a2fc6 --- /dev/null +++ b/test/files/expected-results-for-failing-tests.md @@ -0,0 +1,79 @@ +# Jest Test Results + +![Generic badge](https://img.shields.io/badge/1/6-FAILED-red.svg) +
+ Duration: 3.904 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:44:35.369 UTC
Finish:2024-02-23 20:44:39.273 UTC
Duration:3.904 seconds
+
+
+ Outcome: Failed | Total Tests: 6 | Passed: 5 | Failed: 1 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:1
Failed Tests:1
Passed Test Suites:0
Passed Tests:5
+
+
+ :x: should be able to open the additional reasons drawer and select a reason + + + + + + + + + + + + + + + + + +
Title:should be able to open the additional reasons drawer and select a reason
Status:failed
Location:null
Failure Messages:
Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)
+
+Expected number of calls: 3
+Received number of calls: 1
+    at toHaveBeenCalledTimes (C:\code\Selector.test.js:69:20)
+    at call (C:\code\Selector.test.js:2:1)
+    at Generator.tryCatch (C:\code\Selector.test.js:2:1)
+    at Generator._invoke [as next] (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+
diff --git a/test/files/expected-results-for-no-tests.md b/test/files/expected-results-for-no-tests.md new file mode 100644 index 0000000..38c342a --- /dev/null +++ b/test/files/expected-results-for-no-tests.md @@ -0,0 +1,37 @@ +# Missing Test Results + +![Generic badge](https://img.shields.io/badge/0/0-PASSED-brightgreen.svg) + +
+ Outcome: Passed | Total Tests: 0 | Passed: 0 | Failed: 0 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:0
Total Tests:0
Failed Test Suites:0
Failed Tests:0
Passed Test Suites:0
Passed Tests:0
+
+ +## :grey_question: undefined + +There were no test results to report. diff --git a/test/files/expected-results-for-passing-tests.md b/test/files/expected-results-for-passing-tests.md new file mode 100644 index 0000000..f432d56 --- /dev/null +++ b/test/files/expected-results-for-passing-tests.md @@ -0,0 +1,49 @@ +# Passing Test Results + +![Generic badge](https://img.shields.io/badge/6/6-PASSED-brightgreen.svg) +
+ Duration: 5.688 seconds + + + + + + + + + + + + + +
Start:2024-02-23 13:43:06.979 MST
Finish:2024-02-23 13:43:12.667 MST
Duration:5.688 seconds
+
+
+ Outcome: Passed | Total Tests: 6 | Passed: 6 | Failed: 0 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:0
Failed Tests:0
Passed Test Suites:1
Passed Tests:6
+
diff --git a/test/files/failing.json b/test/files/failing.json new file mode 100644 index 0000000..16e5c04 --- /dev/null +++ b/test/files/failing.json @@ -0,0 +1,131 @@ +{ + "numFailedTestSuites": 1, + "numFailedTests": 1, + "numPassedTestSuites": 0, + "numPassedTests": 5, + "numPendingTestSuites": 0, + "numPendingTests": 0, + "numRuntimeErrorTestSuites": 0, + "numTodoTests": 0, + "numTotalTestSuites": 1, + "numTotalTests": 6, + "openHandles": [], + "snapshot": { + "added": 0, + "didUpdate": false, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0 + }, + "startTime": 1708721075369, + "success": false, + "testResults": [ + { + "assertionResults": [ + { + "ancestorTitles": [], + "duration": 339, + "failureDetails": [], + "failureMessages": [], + "fullName": "should be able to select a recommended reason", + "invocations": 1, + "location": null, + "numPassingAsserts": 3, + "retryReasons": [], + "status": "passed", + "title": "should be able to select a recommended reason" + }, + { + "ancestorTitles": [], + "duration": 187, + "failureDetails": [ + { + "matcherResult": { + "message": "\u001b[2mexpect(\u001b[22m\u001b[31mjest.fn()\u001b[39m\u001b[2m).\u001b[22mtoHaveBeenCalledTimes\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m\n\nExpected number of calls: \u001b[32m3\u001b[39m\nReceived number of calls: \u001b[31m1\u001b[39m", + "pass": false + } + } + ], + "failureMessages": [ + "Error: \u001b[2mexpect(\u001b[22m\u001b[31mjest.fn()\u001b[39m\u001b[2m).\u001b[22mtoHaveBeenCalledTimes\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m\n\nExpected number of calls: \u001b[32m3\u001b[39m\nReceived number of calls: \u001b[31m1\u001b[39m\n at toHaveBeenCalledTimes (C:\\code\\Selector.test.js:69:20)\n at call (C:\\code\\Selector.test.js:2:1)\n at Generator.tryCatch (C:\\code\\Selector.test.js:2:1)\n at Generator._invoke [as next] (C:\\code\\Selector.test.js:2:1)\n at asyncGeneratorStep (C:\\code\\Selector.test.js:2:1)\n at asyncGeneratorStep (C:\\code\\Selector.test.js:2:1)" + ], + "fullName": "should be able to open the additional reasons drawer and select a reason", + "invocations": 1, + "location": null, + "numPassingAsserts": 1, + "retryReasons": [], + "status": "failed", + "title": "should be able to open the additional reasons drawer and select a reason" + }, + { + "ancestorTitles": [], + "duration": 167, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display an error when save is clicked with an invalid event date", + "invocations": 1, + "location": null, + "numPassingAsserts": 2, + "retryReasons": [], + "status": "passed", + "title": "should display an error when save is clicked with an invalid event date" + }, + { + "ancestorTitles": [], + "duration": 76, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display an error when save is clicked without entering a date", + "invocations": 1, + "location": null, + "numPassingAsserts": 2, + "retryReasons": [], + "status": "passed", + "title": "should display an error when save is clicked without entering a date" + }, + { + "ancestorTitles": [], + "duration": 64, + "failureDetails": [], + "failureMessages": [], + "fullName": "should be able to save a reason which doesn't require an event date", + "invocations": 1, + "location": null, + "numPassingAsserts": 3, + "retryReasons": [], + "status": "passed", + "title": "should be able to save a reason which doesn't require an event date" + }, + { + "ancestorTitles": [], + "duration": 169, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display the reason with isDisplayedFirst first", + "invocations": 1, + "location": null, + "numPassingAsserts": 1, + "retryReasons": [], + "status": "passed", + "title": "should display the reason with isDisplayedFirst first" + } + ], + "endTime": 1708721079273, + "message": "\u001b[1m\u001b[31m \u001b[1m● \u001b[22m\u001b[1mshould be able to open the additional reasons drawer and select a reason\u001b[39m\u001b[22m\n\n \u001b[2mexpect(\u001b[22m\u001b[31mjest.fn()\u001b[39m\u001b[2m).\u001b[22mtoHaveBeenCalledTimes\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m)\u001b[22m\n\n Expected number of calls: \u001b[32m3\u001b[39m\n Received number of calls: \u001b[31m1\u001b[39m\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 67 |\u001b[39m screen\u001b[33m.\u001b[39mgetByText(\u001b[32m'Save'\u001b[39m)\u001b[33m.\u001b[39mclick()\u001b[33m;\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 68 |\u001b[39m \u001b[90m//expect onChange to have been called with the correct reason\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m\u001b[31m\u001b[1m>\u001b[22m\u001b[2m\u001b[39m\u001b[90m 69 |\u001b[39m expect(onChange)\u001b[33m.\u001b[39mtoHaveBeenCalledTimes(\u001b[35m3\u001b[39m)\u001b[33m;\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m |\u001b[39m \u001b[31m\u001b[1m^\u001b[22m\u001b[2m\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 70 |\u001b[39m expect(onChange)\u001b[33m.\u001b[39mtoHaveBeenCalledWith({\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 71 |\u001b[39m displayText\u001b[33m:\u001b[39m \u001b[32m'I moved back to the United States after living outside of the country.'\u001b[39m\u001b[33m,\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 72 |\u001b[39m code\u001b[33m:\u001b[39m \u001b[32m'RUS'\u001b[39m\u001b[33m,\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat toHaveBeenCalledTimes (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:69:20)\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat call (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:2:1)\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat Generator.tryCatch (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:2:1)\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat Generator._invoke [as next] (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:2:1)\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat asyncGeneratorStep (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:2:1)\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat asyncGeneratorStep (\u001b[22m\u001b[2m\u001b[0m\u001b[36mApp/components/Selector.test.js\u001b[39m\u001b[0m\u001b[2m:2:1)\u001b[22m\u001b[2m\u001b[22m\n", + "name": "C:\\code\\Selector.test.js", + "startTime": 1708721075810, + "status": "failed", + "summary": "" + } + ], + "wasInterrupted": false +} \ No newline at end of file diff --git a/test/files/no-tests.json b/test/files/no-tests.json new file mode 100644 index 0000000..cd9347c --- /dev/null +++ b/test/files/no-tests.json @@ -0,0 +1,33 @@ +{ + "numFailedTestSuites": 0, + "numFailedTests": 0, + "numPassedTestSuites": 0, + "numPassedTests": 0, + "numPendingTestSuites": 0, + "numPendingTests": 0, + "numRuntimeErrorTestSuites": 0, + "numTodoTests": 0, + "numTotalTestSuites": 0, + "numTotalTests": 0, + "openHandles": [], + "snapshot": { + "added": 0, + "didUpdate": false, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0 + }, + "startTime": 1708720986979, + "success": true, + "testResults": [], + "wasInterrupted": false +} \ No newline at end of file diff --git a/test/files/passing.json b/test/files/passing.json new file mode 100644 index 0000000..5a426b7 --- /dev/null +++ b/test/files/passing.json @@ -0,0 +1,122 @@ +{ + "numFailedTestSuites": 0, + "numFailedTests": 0, + "numPassedTestSuites": 1, + "numPassedTests": 6, + "numPendingTestSuites": 0, + "numPendingTests": 0, + "numRuntimeErrorTestSuites": 0, + "numTodoTests": 0, + "numTotalTestSuites": 1, + "numTotalTests": 6, + "openHandles": [], + "snapshot": { + "added": 0, + "didUpdate": false, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0 + }, + "startTime": 1708720986979, + "success": true, + "testResults": [ + { + "assertionResults": [ + { + "ancestorTitles": [], + "duration": 342, + "failureDetails": [], + "failureMessages": [], + "fullName": "should be able to select a recommended reason", + "invocations": 1, + "location": null, + "numPassingAsserts": 3, + "retryReasons": [], + "status": "passed", + "title": "should be able to select a recommended reason" + }, + { + "ancestorTitles": [], + "duration": 198, + "failureDetails": [], + "failureMessages": [], + "fullName": "should be able to open the additional reasons drawer and select a reason", + "invocations": 1, + "location": null, + "numPassingAsserts": 3, + "retryReasons": [], + "status": "passed", + "title": "should be able to open the additional reasons drawer and select a reason" + }, + { + "ancestorTitles": [], + "duration": 175, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display an error when save is clicked with an invalid event date", + "invocations": 1, + "location": null, + "numPassingAsserts": 2, + "retryReasons": [], + "status": "passed", + "title": "should display an error when save is clicked with an invalid event date" + }, + { + "ancestorTitles": [], + "duration": 75, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display an error when save is clicked without entering a date", + "invocations": 1, + "location": null, + "numPassingAsserts": 2, + "retryReasons": [], + "status": "passed", + "title": "should display an error when save is clicked without entering a date" + }, + { + "ancestorTitles": [], + "duration": 64, + "failureDetails": [], + "failureMessages": [], + "fullName": "should be able to save a reason which doesn't require an event date", + "invocations": 1, + "location": null, + "numPassingAsserts": 3, + "retryReasons": [], + "status": "passed", + "title": "should be able to save a reason which doesn't require an event date" + }, + { + "ancestorTitles": [], + "duration": 169, + "failureDetails": [], + "failureMessages": [], + "fullName": "should display the reason with isDisplayedFirst first", + "invocations": 1, + "location": null, + "numPassingAsserts": 1, + "retryReasons": [], + "status": "passed", + "title": "should display the reason with isDisplayedFirst first" + } + ], + "endTime": 1708720992667, + "message": "", + "name": "C:\\code\\Selector.test.js", + "startTime": 1708720987647, + "status": "passed", + "summary": "" + } + ], + "wasInterrupted": false +} \ No newline at end of file From 9eede81df6045084189236d33421f2f37b8bf826 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Fri, 23 Feb 2024 17:01:14 -0700 Subject: [PATCH 04/14] ARCH-2011 - Adding status check tests & update code to output/return the status check id --- .github/workflows/build-and-review-pr.yml | 200 +++++++++++++++++++++- README.md | 14 +- action.yml | 4 +- dist/index.js | 31 +++- src/github.js | 30 +++- src/main.js | 5 +- 6 files changed, 251 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index 5a25d82..f59f18f 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -101,7 +101,7 @@ jobs: ./test/assert-value-is-empty.sh --name "test-outcome output" --value "${{ steps.missing-github-token.outputs.test-outcome }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.missing-github-token.outputs.test-results-truncated }}" ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.missing-github-token.outputs.test-results-file-path }}" - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.missing-github-token.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.missing-github-token.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-github-token.outputs.pr-comment-id }}" - name: '-------------------------------------------------------------------------------------------------------------' @@ -128,7 +128,7 @@ jobs: ./test/assert-value-is-empty.sh --name "test-outcome output" --value "${{ steps.missing-results-file.outputs.test-outcome }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.missing-results-file.outputs.test-results-truncated }}" ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.missing-results-file.outputs.test-results-file-path }}" - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.missing-results-file.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.missing-results-file.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-results-file.outputs.pr-comment-id }}" - name: '-------------------------------------------------------------------------------------------------------------' @@ -161,7 +161,7 @@ jobs: run: | ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.file-does-not-exist.outputs.test-results-truncated }}" ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.file-does-not-exist.outputs.test-results-file-path }}" - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.file-does-not-exist.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.file-does-not-exist.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.file-does-not-exist.outputs.pr-comment-id }}" @@ -194,7 +194,7 @@ jobs: run: | ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.empty-file.outputs.test-results-truncated }}" ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.empty-file.outputs.test-results-file-path }}" - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.empty-file.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.empty-file.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.empty-file.outputs.pr-comment-id }}" - name: '-------------------------------------------------------------------------------------------------------------' @@ -230,7 +230,7 @@ jobs: - name: 5 - And the remaining outputs should be empty since status checks and pr comments were not created if: always() run: | - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.passing-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.passing-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.passing-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.passing-tests.outputs.test-results-truncated }}" @@ -281,7 +281,7 @@ jobs: - name: 6 - And the remaining outputs should be empty since status checks and pr comments were not created if: always() run: | - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.failing-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.failing-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.failing-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.failing-tests.outputs.test-results-truncated }}" @@ -332,7 +332,7 @@ jobs: - name: 7 - And the remaining outputs should be empty since status checks and pr comments were not created if: always() run: | - ./test/assert-value-is-empty.sh --name "status-check-ids output" --value "${{ steps.no-tests.outputs.status-check-ids }}" + ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.no-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.no-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.no-tests.outputs.test-results-truncated }}" @@ -350,3 +350,189 @@ jobs: expectedFileName="${{ env.NO_TESTS_MD_FILE }}" actualFileName="${{ steps.no-tests.outputs.test-results-file-path }}" ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName + + test-status-checks: + runs-on: ubuntu-latest + env: + FAILING_RESULTS: './test/files/failing.json' + PASSING_RESULTS: './test/files/passing.json' + NO_RESULTS: './test/files/no-tests.json' + FAILING_MD_FILE: './test/files/expected-results-for-failing-tests.md' + PASSING_MD_FILE: './test/files/expected-results-for-passing-tests.md' + NO_TESTS_MD_FILE: './test/files/expected-results-for-no-tests.md' + NO_FAILURES_REPORT_NAME: 'No Failing Tests' + IGNORE_FAILURES_REPORT_NAME: 'Ignore Failing Tests' + ALLOW_FAILURES_REPORT_NAME: 'Allow Failing Tests' + + steps: + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' SETUP ' + run: echo "" + + - name: Setup - Fail test job if fork + run: | + if [ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]; then + echo "This test job requires the `checks: write` scope on the GITHUB_TOKEN which PRs from forks do not have. Before this PR can be merged, the tests should be run on an intermediate branch created by repository owners." + exit 1 + fi + + - name: Setup - Checkout the action + uses: actions/checkout@v4 + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 8 - STATUS CHECK - NO FAILURES ' + run: echo "" + + - name: 8 - When process-jest-test-results is called with no failures + if: always() + id: no-failures + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: ${{ env.PASSING_RESULTS }} + report-name: ${{ env.NO_FAILURES_REPORT_NAME }} + create-status-check: true + create-pr-comment: false + + - name: 8 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.no-failures.outcome }}" + + - name: 8 - And the status-check-id output should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.no-failures.outputs.status-check-id }}" + + - name: 8 - And the test-outcome output should be Passed + if: always() + run: ./test/assert-values-match.sh --name "test-outcome output" --expected "Passed" --actual "${{ steps.no-failures.outputs.test-outcome }}" + + - name: 8 - And the status check should match the inputs + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); + + const checkId = '${{ steps.no-failures.outputs.status-check-id }}'; + const actualCheck = await assertStatusCheckExists(github, core, checkId); + const expectedBody = fs.readFileSync('${{ env.PASSING_MD_FILE }}', 'utf8'); + + const expectedValues = { + name: 'status check - ${{ env.NO_FAILURES_REPORT_NAME }}'.toLowerCase(), + status: 'completed', + conclusion: 'success', + title: '${{ env.NO_FAILURES_REPORT_NAME }}', + text: expectedBody + }; + assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 9 - STATUS CHECK - IGNORE FAILURES ' + run: echo "" + + - name: 9 - When process-jest-test-results is called with test failures & ignore-test-failures=true + if: always() + id: ignore-failures + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: ${{ env.FAILING_RESULTS }} + report-name: ${{ env.IGNORE_FAILURES_REPORT_NAME }} + create-status-check: true + ignore-test-failures: true + create-pr-comment: false + + - name: 9 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.ignore-failures.outcome }}" + + - name: 9 - And the status-check-id output should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.ignore-failures.outputs.status-check-id }}" + + - name: 9 - And the test-outcome output should be Failed + if: always() + run: ./test/assert-values-match.sh --name "test-outcome output" --expected "Failed" --actual "${{ steps.ignore-failures.outputs.test-outcome }}" + + - name: 9 - And the status check should match the inputs + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); + + const checkId = '${{ steps.ignore-failures.outputs.status-check-id }}'; + const actualCheck = await assertStatusCheckExists(github, core, checkId); + const expectedBody = fs.readFileSync('${{ env.FAILING_MD_FILE }}', 'utf8'); + + const expectedValues = { + name: 'status check - ${{ env.IGNORE_FAILURES_REPORT_NAME }}'.toLowerCase(), + status: 'completed', + conclusion: 'neutral', + title: '${{ env.IGNORE_FAILURES_REPORT_NAME }}', + text: expectedBody + }; + assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 10 - STATUS CHECK - ALLOW FAILURES ' + run: echo "" + + - name: 10 - When process-jest-test-results is called with test failures & ignore-test-failures=false + if: always() + id: allow-failures + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + results-file: ${{ env.FAILING_RESULTS }} + report-name: ${{ env.ALLOW_FAILURES_REPORT_NAME }} + create-status-check: true + ignore-test-failures: false + create-pr-comment: false + + - name: 10 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.allow-failures.outcome }}" + + - name: 10 - And the status-check-id output should be populated + if: always() + run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.allow-failures.outputs.status-check-id }}" + + - name: 10 - And the test-outcome output should be Failed + if: always() + run: ./test/assert-values-match.sh --name "test-outcome output" --expected "Failed" --actual "${{ steps.allow-failures.outputs.test-outcome }}" + + - name: 10 - And the status check should match the inputs + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); + + const checkId = '${{ steps.allow-failures.outputs.status-check-id }}'; + const actualCheck = await assertStatusCheckExists(github, core, checkId); + const expectedBody = fs.readFileSync('${{ env.FAILING_MD_FILE }}', 'utf8'); + + const expectedValues = { + name: 'status check - ${{ env.ALLOW_FAILURES_REPORT_NAME }}'.toLowerCase(), + status: 'completed', + conclusion: 'failure', + title: '${{ env.ALLOW_FAILURES_REPORT_NAME }}', + text: expectedBody + }; + assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + + \ No newline at end of file diff --git a/README.md b/README.md index 9d4325d..17889b6 100644 --- a/README.md +++ b/README.md @@ -81,13 +81,13 @@ For failed test runs you can expand each failed test and view more details about ## Outputs -| Output | Description | -|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `test-outcome` | Test outcome based on presence of failing tests: *Failed,Passed*
If exceptions are thrown or if it exits early because of argument errors, this is set to Failed. | -| `test-results-truncated` | Flag indicating whether test results were truncated due to markdown exceeding character limit of 65535. | -| `test-results-file-path` | File path for the file that contains the pre-truncated test results in markdown format. This is the same output that is posted in the PR comment. | -| `status-check-ids` | A comma-separated string of IDs for any status checks that were created. This is only set if `create-status-check` is `true` and one or more status checks were created successfully. | -| `pr-comment-id` | The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully. | +| Output | Description | +|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `test-outcome` | Test outcome based on presence of failing tests: *Failed,Passed*
If exceptions are thrown or if it exits early because of argument errors, this is set to Failed. | +| `test-results-truncated` | Flag indicating whether test results were truncated due to markdown exceeding character limit of 65535. | +| `test-results-file-path` | File path for the file that contains the pre-truncated test results in markdown format. This is the same output that is posted in the PR comment. | +| `status-check-id` | The ID of the Status Check that was created. This is only set if `create-status-check` is `true` and a status check was created successfully. | +| `pr-comment-id` | The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully. | ## Usage Examples diff --git a/action.yml b/action.yml index 5691bc4..f37e991 100644 --- a/action.yml +++ b/action.yml @@ -43,8 +43,8 @@ outputs: description: 'Flag indicating whether test results were truncated due to markdown exceeding character limit of 65535.' test-results-file-path: description: 'File path for the file that contains the pre-truncated test results in markdown format. This is the same output that is posted in the PR comment.' - status-check-ids: - description: 'A comma-separated string of IDs for any status checks that were created. This is only set if `create-status-check` is `true` and one or more status checks were created successfully.' + status-check-id: + description: 'The ID of the Status Check that was created. This is only set if `create-status-check` is `true` and a status check was created successfully.' pr-comment-id: description: 'The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully.' diff --git a/dist/index.js b/dist/index.js index 56c82a8..0425765 100644 --- a/dist/index.js +++ b/dist/index.js @@ -16653,33 +16653,47 @@ var require_github2 = __commonJS({ var github = require_github(); var markupPrefix = ''; async function createStatusCheck2(repoToken, markupData, conclusion, reportName2) { - core2.info(`Creating Status check for ${reportName2}...`); + core2.info(` +Creating Status check for ${reportName2}...`); const octokit = github.getOctokit(repoToken); const git_sha = github.context.eventName === 'pull_request' ? github.context.payload.pull_request.head.sha : github.context.sha; - core2.info(`Creating status check for GitSha: ${git_sha} on a ${github.context.eventName} event.`); + const name = `status check - ${reportName2.toLowerCase()}`; + const status = 'completed'; const checkTime = new Date().toUTCString(); - core2.info(`Check time is: ${checkTime}`); + const summary = `This test run completed at \`${checkTime}\``; + let propMessage = ` Name: ${name} + GitSha: ${git_sha} + Event: ${github.context.eventName} + Status: ${status} + Conclusion: ${conclusion} + Check time: ${checkTime} + Title: ${reportName2} + Summary: ${summary}`; + core2.info(propMessage); + let statusCheckId; await octokit.rest.checks .create({ owner: github.context.repo.owner, repo: github.context.repo.repo, - name: `status check - ${reportName2.toLowerCase()}`, + name, head_sha: git_sha, - status: 'completed', + status, conclusion, output: { title: reportName2, - summary: `This test run completed at \`${checkTime}\``, + summary, text: markupData } }) .then(response => { - core2.info(`Created check: ${response.data.name}`); + core2.info(`Created check: '${response.data.name}' with id '${response.data.id}'`); + statusCheckId = response.data.id; }) .catch(error => { core2.setFailed(`An error occurred trying to create the status check: ${error.message}`); }); + return statusCheckId; } async function lookForExistingComment(octokit) { let commentId = null; @@ -19810,7 +19824,8 @@ async function run() { if (!resultsJson.success) { conclusion = ignoreTestFailures ? 'neutral' : 'failure'; } - await createStatusCheck(token, markupData, conclusion, reportName); + const checkId = await createStatusCheck(token, markupData, conclusion, reportName); + core.setOutput('status-check-id', checkId); } if (shouldCreatePRComment) { await createPrComment(token, markupData, updateCommentIfOneExists); diff --git a/src/github.js b/src/github.js index 5e2061a..5660cb3 100644 --- a/src/github.js +++ b/src/github.js @@ -3,36 +3,49 @@ const github = require('@actions/github'); const markupPrefix = ''; async function createStatusCheck(repoToken, markupData, conclusion, reportName) { - core.info(`Creating Status check for ${reportName}...`); + core.info(`\nCreating Status check for ${reportName}...`); const octokit = github.getOctokit(repoToken); const git_sha = github.context.eventName === 'pull_request' ? github.context.payload.pull_request.head.sha : github.context.sha; - core.info(`Creating status check for GitSha: ${git_sha} on a ${github.context.eventName} event.`); - + const name = `status check - ${reportName.toLowerCase()}`; + const status = 'completed'; const checkTime = new Date().toUTCString(); - core.info(`Check time is: ${checkTime}`); + const summary = `This test run completed at \`${checkTime}\``; + + let propMessage = ` Name: ${name} + GitSha: ${git_sha} + Event: ${github.context.eventName} + Status: ${status} + Conclusion: ${conclusion} + Check time: ${checkTime} + Title: ${reportName} + Summary: ${summary}`; + core.info(propMessage); + let statusCheckId; await octokit.rest.checks .create({ owner: github.context.repo.owner, repo: github.context.repo.repo, - name: `status check - ${reportName.toLowerCase()}`, + name: name, head_sha: git_sha, - status: 'completed', + status: status, conclusion: conclusion, output: { title: reportName, - summary: `This test run completed at \`${checkTime}\``, + summary: summary, text: markupData } }) .then(response => { - core.info(`Created check: ${response.data.name}`); + core.info(`Created check: '${response.data.name}' with id '${response.data.id}'`); + statusCheckId = response.data.id; }) .catch(error => { core.setFailed(`An error occurred trying to create the status check: ${error.message}`); }); + return statusCheckId; } async function lookForExistingComment(octokit) { @@ -82,6 +95,7 @@ async function createPrComment(repoToken, markupData, updateCommentIfOneExists) if (existingCommentId) { core.info(`Updating existing PR #${existingCommentId} comment...`); + await octokit.rest.issues .updateComment({ owner: github.context.repo.owner, diff --git a/src/main.js b/src/main.js index 92cdabe..6fb4e94 100644 --- a/src/main.js +++ b/src/main.js @@ -39,10 +39,13 @@ async function run() { if (!resultsJson.success) { conclusion = ignoreTestFailures ? 'neutral' : 'failure'; } - await createStatusCheck(token, markupData, conclusion, reportName); + const checkId = await createStatusCheck(token, markupData, conclusion, reportName); + core.setOutput('status-check-id', checkId); // This is mainly for testing purposes } if (shouldCreatePRComment) { + // GitHub API has a limit of 65535 characters for a comment so truncate the markup if we need to + await createPrComment(token, markupData, updateCommentIfOneExists); } } catch (error) { From 9a9a0dbceee066ce5e9118690200e078f12a0e36 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Mon, 26 Feb 2024 13:34:45 -0700 Subject: [PATCH 05/14] ARCH-2011 - Fix assertion for status check & add check cleanup --- .github/workflows/build-and-review-pr.yml | 316 ++++++++++++++++-- test/assert-status-check-exists.js | 41 +++ ...ssert-status-check-matches-expectations.js | 5 +- test/assert-status-checks-exist.js | 42 --- .../expected-check-results-allow-failures.md | 79 +++++ .../expected-check-results-ignore-failures.md | 79 +++++ .../expected-check-results-no-failures.md | 49 +++ test/update-failing-status-check.js | 51 +++ 8 files changed, 597 insertions(+), 65 deletions(-) create mode 100644 test/assert-status-check-exists.js delete mode 100644 test/assert-status-checks-exist.js create mode 100644 test/files/expected-check-results-allow-failures.md create mode 100644 test/files/expected-check-results-ignore-failures.md create mode 100644 test/files/expected-check-results-no-failures.md create mode 100644 test/update-failing-status-check.js diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index f59f18f..8069c90 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -354,15 +354,16 @@ jobs: test-status-checks: runs-on: ubuntu-latest env: - FAILING_RESULTS: './test/files/failing.json' - PASSING_RESULTS: './test/files/passing.json' - NO_RESULTS: './test/files/no-tests.json' - FAILING_MD_FILE: './test/files/expected-results-for-failing-tests.md' - PASSING_MD_FILE: './test/files/expected-results-for-passing-tests.md' - NO_TESTS_MD_FILE: './test/files/expected-results-for-no-tests.md' - NO_FAILURES_REPORT_NAME: 'No Failing Tests' - IGNORE_FAILURES_REPORT_NAME: 'Ignore Failing Tests' - ALLOW_FAILURES_REPORT_NAME: 'Allow Failing Tests' + FAILING_TESTS_JSON: './test/files/failing.json' + PASSING_TESTS_JSON: './test/files/passing.json' + + NO_FAILURES_MARKUP: './test/files/expected-check-results-no-failures.md' + IGNORE_FAILURES_MARKUP: './test/files/expected-check-results-ignore-failures.md' + ALLOW_FAILURES_MARKUP: './test/files/expected-check-results-allow-failures.md' + + NO_FAILURES_REPORT_NAME: 'No Failures Scenario' + IGNORE_FAILURES_REPORT_NAME: 'Ignore Failures Scenario' + ALLOW_FAILURES_REPORT_NAME: 'Allow Failures Scenario' steps: - name: '-------------------------------------------------------------------------------------------------------------' @@ -391,7 +392,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.PASSING_RESULTS }} + results-file: ${{ env.PASSING_TESTS_JSON }} report-name: ${{ env.NO_FAILURES_REPORT_NAME }} create-status-check: true create-pr-comment: false @@ -414,12 +415,12 @@ jobs: with: script: | const fs = require('fs'); - const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckExists = require('./test/assert-status-check-exists.js'); const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.no-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.PASSING_MD_FILE }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MARKUP }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.NO_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -441,7 +442,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.FAILING_RESULTS }} + results-file: ${{ env.FAILING_TESTS_JSON }} report-name: ${{ env.IGNORE_FAILURES_REPORT_NAME }} create-status-check: true ignore-test-failures: true @@ -465,12 +466,12 @@ jobs: with: script: | const fs = require('fs'); - const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckExists = require('./test/assert-status-check-exists.js'); const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.ignore-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.FAILING_MD_FILE }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.IGNORE_FAILURES_MARKUP }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.IGNORE_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -492,7 +493,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.FAILING_RESULTS }} + results-file: ${{ env.FAILING_TESTS_JSON }} report-name: ${{ env.ALLOW_FAILURES_REPORT_NAME }} create-status-check: true ignore-test-failures: false @@ -516,12 +517,12 @@ jobs: with: script: | const fs = require('fs'); - const assertStatusCheckExists = require('./test/assert-status-checks-exist.js'); + const assertStatusCheckExists = require('./test/assert-status-check-exists.js'); const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.allow-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.FAILING_MD_FILE }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.ALLOW_FAILURES_MARKUP }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.ALLOW_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -534,5 +535,282 @@ jobs: - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" + - name: ' TEARDOWN ' + run: echo "" + + - name: Teardown - Modify failing Status Check conclusion + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const updateFailingStatusCheck = require('./test/update-failing-status-check.js'); + + await updateFailingStatusCheck(github, core, '${{ steps.allow-failures.outputs.status-check-id }}'); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + + test-pr-comments: + runs-on: ubuntu-latest + if: 1 == 2 + env: + NO_FAILURES_DIR: './test/files/multiple-trx' + TRUNCATE_DIR: './test/files/truncate' + EXISTING_COMMENT_ID: '' + COMMENT_IDENTIFIER: 'existing-comment-${{ github.run_id }}' + + steps: + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' SETUP ' + run: echo "" + + - name: Setup - Fail test job if fork + run: | + if [ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]; then + echo "This test job requires the `pull_request: write` scope on the GITHUB_TOKEN which PRs from forks do not have. Before this PR can be merged, the tests should be run on an intermediate branch created by repository owners." + exit 1 + fi + + - name: Setup - Checkout the action + uses: actions/checkout@v4 + + - name: Setup - Create a comment that can be updated + if: always() + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '\nThis comment will be replaced soon.' + }) + .then(response => { + core.exportVariable('EXISTING_COMMENT_ID', response.data.id); + }) + .catch(error => { + core.setFailed(`An error occurred in the setup step while creating a comment: ${error.message}`); + }); + await new Promise(r => setTimeout(r, 5 * 1000)); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 11 - PR COMMENT - UPDATE W/ MATCHING PREFIX ' + run: echo "" + + - name: 11 - When process-jest-test-results is called with updateComment=true and there is a comment with matching prefix + if: always() + id: update-with-matching-prefix + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + base-directory: ${{ env.NO_FAILURES_DIR }} + create-results-file: true # Keep this so we can compare the comment contents to the expected contents + create-status-check: false + create-pr-comment: true + update-comment-if-one-exists: true + comment-identifier: ${{ env.COMMENT_IDENTIFIER }} + + - name: 11 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.update-with-matching-prefix.outcome }}" + + - name: 11 - And the pr-comment-id output should match the existing comment id + if: always() + run: ./test/assert-values-match.sh --name "pr-comment-id output" --expected "${{ env.EXISTING_COMMENT_ID }}" --actual "${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}" + + - name: 11 - And the test-results-truncated output should be false + if: always() + run: ./test/assert-values-match.sh --name "test-results-truncated output" --expected "false" --actual "${{ steps.update-with-matching-prefix.outputs.test-results-truncated }}" + + - name: 11 - And the pr-comment should match the match the expected values + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertCommentExists = require('./test/assert-pr-comment-exists.js'); + const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); + + const commentId = '${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}'; + const actualComment = await assertCommentExists(github, core, commentId); + + const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedPrefix = ''; + const expectedComment = { + prefixAndBody: `${expectedPrefix}\n${expectedBody}`, + action: 'updated' + }; + assertCommentMatchesExpectations(core, actualComment, expectedComment); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 12 - PR COMMENT - UPDATE W/O MATCHING PREFIX ' + run: echo "" + + - name: 12 - When process-jest-test-results is called with updateComment=true but there is no comment with matching prefix + if: always() + id: update-without-matching-prefix + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + base-directory: ${{ env.NO_FAILURES_DIR }} + create-results-file: true # Keep this so we can compare the comment contents to the expected contents + create-status-check: false + create-pr-comment: true + update-comment-if-one-exists: true + comment-identifier: 'different-identifier-${{ github.run_id }}' + + - name: 12 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.update-without-matching-prefix.outcome }}" + + - name: 12 - And the pr-comment-id output should be different than the existing comment id + if: always() + run: ./test/assert-values-do-not-match.sh --name "pr-comment-id output" --value1 "${{ env.EXISTING_COMMENT_ID }}" --value2 "${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}" + + - name: 12 - And the test-results-truncated output should be false + if: always() + run: ./test/assert-values-match.sh --name "test-results-truncated output" --expected "false" --actual "${{ steps.update-without-matching-prefix.outputs.test-results-truncated }}" + + - name: 12 - And the pr-comment should match the expected values + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertCommentExists = require('./test/assert-pr-comment-exists.js'); + const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); + + const commentId = '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'; + const actualComment = await assertCommentExists(github, core, commentId); + + const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedPrefix = ''; + const expectedComment = { + prefixAndBody: `${expectedPrefix}\n${expectedBody}`, + action: 'created' + }; + assertCommentMatchesExpectations(core, actualComment, expectedComment); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 13 - PR COMMENT - NO UPDATE ' + run: echo "" + + - name: 13 - When process-jest-test-results is called with updateComment=false + if: always() + id: matching-prefix-no-update + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + base-directory: ${{ env.NO_FAILURES_DIR }} + create-results-file: true # Keep this so we can compare the comment contents to the expected contents + create-status-check: false + create-pr-comment: true + update-comment-if-one-exists: false + + - name: 13 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.matching-prefix-no-update.outcome }}" + + - name: 13 - And the pr-comment-id output should be different than the existing comment id + if: always() + run: ./test/assert-values-do-not-match.sh --name "pr-comment-id output" --value1 "${{ env.EXISTING_COMMENT_ID }}" --value2 "${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}" + + - name: 13 - And the test-results-truncated output should be false + if: always() + run: ./test/assert-values-match.sh --name "test-results-truncated output" --expected "false" --actual "${{ steps.matching-prefix-no-update.outputs.test-results-truncated }}" + + - name: 13 - And the pr-comment should match the expected values + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertCommentExists = require('./test/assert-pr-comment-exists.js'); + const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); + + const commentId = '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'; + const actualComment = await assertCommentExists(github, core, commentId); + + const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedPrefix = ''; + const expectedComment = { + prefixAndBody: `${expectedPrefix}\n${expectedBody}`, + action: 'created' + }; + assertCommentMatchesExpectations(core, actualComment, expectedComment); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEST 14 - PR COMMENT - TRUNCATE ' + run: echo "" + + - name: 14 - When process-jest-test-results is called with a large comment that needs to be truncated + if: always() + id: truncate + uses: ./ + with: + github-token: '${{ secrets.GITHUB_TOKEN }}' + base-directory: ${{ env.TRUNCATE_DIR }} + create-results-file: true # Keep this so we can compare the comment contents to the expected contents + create-status-check: false + create-pr-comment: true + update-comment-if-one-exists: true + comment-identifier: ${{ env.COMMENT_IDENTIFIER }} + + - name: 14 - Then the action outcome should be success + if: always() + run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.truncate.outcome }}" + + - name: 14 - And the pr-comment-id output should match the existing comment id + if: always() + run: ./test/assert-values-match.sh --name "pr-comment-id output" --expected "${{ env.EXISTING_COMMENT_ID }}" --actual "${{ steps.truncate.outputs.pr-comment-id }}" + + - name: 14 - And the test-results-truncated output should be true + if: always() + run: ./test/assert-values-match.sh --name "test-results-truncated output" --expected "true" --actual "${{ steps.truncate.outputs.test-results-truncated }}" + + - name: 14 - And the pr-comment should match the expected values + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const assertCommentExists = require('./test/assert-pr-comment-exists.js'); + const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); + + const commentId = '${{ steps.truncate.outputs.pr-comment-id }}'; + const actualComment = await assertCommentExists(github, core, commentId); + + const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedPrefix = ''; + const expectedComment = { + prefixAndBody: `${expectedPrefix}\nTest results truncated due to character limit. See full report in output. \n${expectedBody}`, + action: 'updated' + }; + + assertCommentMatchesExpectations(core, actualComment, expectedComment); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" + - name: ' TEARDOWN ' + run: echo "" - \ No newline at end of file + - name: Teardown - Delete PR Comments + if: always() + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const deletePrComment = require('./test/delete-pr-comment.js'); + + await deletePrComment(github, core, '${{ env.EXISTING_COMMENT_ID }}'); + await deletePrComment(github, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'); + await deletePrComment(github, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'); + + - name: '-------------------------------------------------------------------------------------------------------------' + run: echo "" \ No newline at end of file diff --git a/test/assert-status-check-exists.js b/test/assert-status-check-exists.js new file mode 100644 index 0000000..b3172ae --- /dev/null +++ b/test/assert-status-check-exists.js @@ -0,0 +1,41 @@ +module.exports = async (github, core, statusCheckId) => { + core.info(`\nAsserting that status check '${statusCheckId} exists`); + + if (!statusCheckId || statusCheckId.trim() === '') { + core.setFailed('The statusCheckId was not provided'); + return; + } + + let statusCheckToReturn; + await github.rest.checks + .get({ + owner: 'im-open', + repo: 'process-jest-test-results', + check_run_id: statusCheckId.trim() + }) + .then(checkResponse => { + core.info(`Status Check ${statusCheckId} exists.`); + const rawCheck = checkResponse.data; + + statusCheckToReturn = { + id: rawCheck.id, + name: rawCheck.name, + status: rawCheck.status, + conclusion: rawCheck.conclusion, + startedAt: rawCheck.started_at, + completedAt: rawCheck.completed_at, + title: rawCheck.output.title, + summary: rawCheck.output.summary, + prNumber: rawCheck.pull_requests.length > 0 ? rawCheck.pull_requests[0].number : null, + text: rawCheck.output.text + }; + core.startGroup(`Check ${statusCheckId} details:`); + console.log(statusCheckToReturn); + core.endGroup(); + }) + .catch(error => { + core.setFailed(`An error occurred retrieving status check ${statusCheckId}. Error: ${error.message}`); + }); + + return statusCheckToReturn; +}; diff --git a/test/assert-status-check-matches-expectations.js b/test/assert-status-check-matches-expectations.js index 7a1678c..d5a7fc5 100644 --- a/test/assert-status-check-matches-expectations.js +++ b/test/assert-status-check-matches-expectations.js @@ -30,14 +30,11 @@ module.exports = async (core, statusCheck, expectedValues) => { assertValuesMatch('Status', expectedValues['status'], statusCheck.status); assertValuesMatch('Conclusion', expectedValues['conclusion'], statusCheck.conclusion); assertValuesMatch('Title', expectedValues['title'], statusCheck.title); + assertValuesMatch('Text', expectedValues['text'], statusCheck.text); // The summary should be something like: 'This test run completed at `Wed, 21 Feb 2024 20:21:48 GMT`' // so just check that it contains the static portion. assertValueContainsSubstring('Summary', statusCheck.summary, 'This test run completed at `'); - - // The text will be a just the markdown for a single trx file. Check that the expected text - // (which is the markdown for all trx files) contains the subset. - assertValueContainsSubstring('Text', expectedValues['text'], statusCheck.text); } validateProps(); diff --git a/test/assert-status-checks-exist.js b/test/assert-status-checks-exist.js deleted file mode 100644 index b22581b..0000000 --- a/test/assert-status-checks-exist.js +++ /dev/null @@ -1,42 +0,0 @@ -module.exports = async (github, core, statusCheckIds) => { - core.info(`\nAsserting that checks with the following ids exist: '${statusCheckIds}'`); - - const actualChecks = []; - const checkIds = statusCheckIds.split(','); - for (const checkId of checkIds) { - if (!checkId || checkId.trim() === '') { - continue; - } - - core.startGroup(`Checking for the existence of status check ${checkId}.`); - const checkResponse = await github.rest.checks.get({ - owner: 'im-open', - repo: 'process-jest-test-results', - check_run_id: checkId.trim() - }); - if (!checkResponse && !checkResponse.data) { - core.setFailed(`Status Check ${checkId} does not appear to exist.`); - } else { - core.info(`Status Check ${checkId} exists.`); - let rawCheck = checkResponse.data; - - const check = { - id: rawCheck.id, - name: rawCheck.name, - status: rawCheck.status, - conclusion: rawCheck.conclusion, - startedAt: rawCheck.started_at, - completedAt: rawCheck.completed_at, - title: rawCheck.output.title, - summary: rawCheck.output.summary, - prNumber: rawCheck.pull_requests.length > 0 ? rawCheck.pull_requests[0].number : null, - text: rawCheck.output.text - }; - core.info(`Check ${check.id} details:`); - console.log(check); - actualChecks.push(check); - } - core.endGroup(); - } - return actualChecks; -}; diff --git a/test/files/expected-check-results-allow-failures.md b/test/files/expected-check-results-allow-failures.md new file mode 100644 index 0000000..f202d6d --- /dev/null +++ b/test/files/expected-check-results-allow-failures.md @@ -0,0 +1,79 @@ +# Allow Failures Scenario + +![Generic badge](https://img.shields.io/badge/1/6-FAILED-red.svg) +
+ Duration: 3.904 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:44:35.369 UTC
Finish:2024-02-23 20:44:39.273 UTC
Duration:3.904 seconds
+
+
+ Outcome: Failed | Total Tests: 6 | Passed: 5 | Failed: 1 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:1
Failed Tests:1
Passed Test Suites:0
Passed Tests:5
+
+
+ :x: should be able to open the additional reasons drawer and select a reason + + + + + + + + + + + + + + + + + +
Title:should be able to open the additional reasons drawer and select a reason
Status:failed
Location:null
Failure Messages:
Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)
+
+Expected number of calls: 3
+Received number of calls: 1
+    at toHaveBeenCalledTimes (C:\code\Selector.test.js:69:20)
+    at call (C:\code\Selector.test.js:2:1)
+    at Generator.tryCatch (C:\code\Selector.test.js:2:1)
+    at Generator._invoke [as next] (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+
diff --git a/test/files/expected-check-results-ignore-failures.md b/test/files/expected-check-results-ignore-failures.md new file mode 100644 index 0000000..4a3cd3d --- /dev/null +++ b/test/files/expected-check-results-ignore-failures.md @@ -0,0 +1,79 @@ +# Ignore Failures Scenario + +![Generic badge](https://img.shields.io/badge/1/6-FAILED-red.svg) +
+ Duration: 3.904 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:44:35.369 UTC
Finish:2024-02-23 20:44:39.273 UTC
Duration:3.904 seconds
+
+
+ Outcome: Failed | Total Tests: 6 | Passed: 5 | Failed: 1 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:1
Failed Tests:1
Passed Test Suites:0
Passed Tests:5
+
+
+ :x: should be able to open the additional reasons drawer and select a reason + + + + + + + + + + + + + + + + + +
Title:should be able to open the additional reasons drawer and select a reason
Status:failed
Location:null
Failure Messages:
Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)
+
+Expected number of calls: 3
+Received number of calls: 1
+    at toHaveBeenCalledTimes (C:\code\Selector.test.js:69:20)
+    at call (C:\code\Selector.test.js:2:1)
+    at Generator.tryCatch (C:\code\Selector.test.js:2:1)
+    at Generator._invoke [as next] (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+    at asyncGeneratorStep (C:\code\Selector.test.js:2:1)
+
diff --git a/test/files/expected-check-results-no-failures.md b/test/files/expected-check-results-no-failures.md new file mode 100644 index 0000000..67442e8 --- /dev/null +++ b/test/files/expected-check-results-no-failures.md @@ -0,0 +1,49 @@ +# No Failures Scenario + +![Generic badge](https://img.shields.io/badge/6/6-PASSED-brightgreen.svg) +
+ Duration: 5.688 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:43:06.979 UTC
Finish:2024-02-23 20:43:12.667 UTC
Duration:5.688 seconds
+
+
+ Outcome: Passed | Total Tests: 6 | Passed: 6 | Failed: 0 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:0
Failed Tests:0
Passed Test Suites:1
Passed Tests:6
+
diff --git a/test/update-failing-status-check.js b/test/update-failing-status-check.js new file mode 100644 index 0000000..b4d9a1a --- /dev/null +++ b/test/update-failing-status-check.js @@ -0,0 +1,51 @@ +module.exports = async (github, core, statusCheckId) => { + core.info(`\nUpdate purposely failing status checks: '${statusCheckId}'`); + + if (!statusCheckId || statusCheckId.trim() === '') { + return; + } + + let actualCheck; + await github.rest.checks + .get({ + owner: 'im-open', + repo: 'process-jest-test-results', + check_run_id: statusCheckId + }) + .then(response => { + core.info(`Status Check ${statusCheckId} exists.`); + actualCheck = response.data; + }) + .catch(error => { + core.setFailed(`An error occurred retrieving status check ${statusCheckId}. Error: ${error.message}`); + }); + + if (!actualCheck) { + core.info('Returning since status check was not found.'); + return; + } + + const updatedText = `> [!IMPORTANT] +> This status check was purposely created with a \`failure\` conclusion. We don't want this to prevent the PR from being merged though, so change the conclusion to \`neutral\` after the tests have run. +${actualCheck.output.text}`; + await github.rest.checks + .update({ + owner: 'im-open', + repo: 'process-jest-test-results', + check_run_id: statusCheckId, + name: `${actualCheck.name} - UPDATED`, + conclusion: 'neutral', + output: { + title: `${actualCheck.output.title}`, + summary: `${actualCheck.output.summary}`, + text: updatedText + } + }) + .then(() => { + core.info(`The status check '${statusCheckId}' was updated successfully.`); + }) + .catch(error => { + core.info(`An error occurred updating status check '${statusCheckId}'. Error: ${error.message}`); + core.info(`This status check can be ignored when determining whether the PR is ready to merge.`); + }); +}; From c601688397862cc62cca7332f9a08ae7bb51bf54 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Mon, 26 Feb 2024 16:04:08 -0700 Subject: [PATCH 06/14] ARCH-2011 - Adding truncate & comment-identifier functionality to the action --- .github/workflows/build-and-review-pr.yml | 58 +++--- README.md | 21 +- action.yml | 23 +- dist/index.js | 40 +++- src/github.js | 12 +- src/main.js | 23 +- src/utils.js | 6 +- test/files/truncate.json | 242 ++++++++++++++++++++++ 8 files changed, 363 insertions(+), 62 deletions(-) create mode 100644 test/files/truncate.json diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index 8069c90..69197e6 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -64,8 +64,8 @@ jobs: unit-tests: runs-on: ubuntu-latest env: - FAILING_MD_FILE: './test/files/expected-results-for-failing-tests.md' PASSING_MD_FILE: './test/files/expected-results-for-passing-tests.md' + FAILING_MD_FILE: './test/files/expected-results-for-failing-tests.md' NO_TESTS_MD_FILE: './test/files/expected-results-for-no-tests.md' steps: @@ -357,9 +357,9 @@ jobs: FAILING_TESTS_JSON: './test/files/failing.json' PASSING_TESTS_JSON: './test/files/passing.json' - NO_FAILURES_MARKUP: './test/files/expected-check-results-no-failures.md' - IGNORE_FAILURES_MARKUP: './test/files/expected-check-results-ignore-failures.md' - ALLOW_FAILURES_MARKUP: './test/files/expected-check-results-allow-failures.md' + NO_FAILURES_MD_FILE: './test/files/expected-check-results-no-failures.md' + IGNORE_FAILURES_MD_FILE: './test/files/expected-check-results-ignore-failures.md' + ALLOW_FAILURES_MD_FILE: './test/files/expected-check-results-allow-failures.md' NO_FAILURES_REPORT_NAME: 'No Failures Scenario' IGNORE_FAILURES_REPORT_NAME: 'Ignore Failures Scenario' @@ -420,7 +420,7 @@ jobs: const checkId = '${{ steps.no-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MARKUP }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.NO_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -471,7 +471,7 @@ jobs: const checkId = '${{ steps.ignore-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.IGNORE_FAILURES_MARKUP }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.IGNORE_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.IGNORE_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -522,7 +522,7 @@ jobs: const checkId = '${{ steps.allow-failures.outputs.status-check-id }}'; const actualCheck = await assertStatusCheckExists(github, core, checkId); - const expectedBody = fs.readFileSync('${{ env.ALLOW_FAILURES_MARKUP }}', 'utf8'); + const expectedBody = fs.readFileSync('${{ env.ALLOW_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { name: 'status check - ${{ env.ALLOW_FAILURES_REPORT_NAME }}'.toLowerCase(), @@ -553,13 +553,22 @@ jobs: test-pr-comments: runs-on: ubuntu-latest - if: 1 == 2 env: - NO_FAILURES_DIR: './test/files/multiple-trx' - TRUNCATE_DIR: './test/files/truncate' EXISTING_COMMENT_ID: '' COMMENT_IDENTIFIER: 'existing-comment-${{ github.run_id }}' + TRUNCATE_TESTS_JSON: './test/files/truncate.json' + PASSING_TESTS_JSON: './test/files/passing.json' + + NO_FAILURES_MD_FILE: './test/files/expected-check-results-no-failures.md' + IGNORE_FAILURES_MD_FILE: './test/files/expected-check-results-ignore-failures.md' + ALLOW_FAILURES_MD_FILE: './test/files/expected-check-results-allow-failures.md' + + NO_FAILURES_REPORT_NAME: 'No Failures Scenario' + TRUNCATE_FAILURES_REPORT_NAME: 'Truncate Failures Scenario' + + + steps: - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -581,11 +590,12 @@ jobs: uses: actions/github-script@v7 with: script: | + const commentIdentifier = '${{ env.GITHUB_JOB }}-${{ env.GITHUB_ACTION }}'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: '\nThis comment will be replaced soon.' + body: `\nThis comment will be replaced soon.` }) .then(response => { core.exportVariable('EXISTING_COMMENT_ID', response.data.id); @@ -606,8 +616,8 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - base-directory: ${{ env.NO_FAILURES_DIR }} - create-results-file: true # Keep this so we can compare the comment contents to the expected contents + results-file: ${{ env.PASSING_TESTS_JSON }} + report-name: ${{ env.NO_FAILURES_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: true @@ -637,7 +647,7 @@ jobs: const commentId = '${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, core, commentId); - const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedBody = fs.readFileSync('${{ steps.update-with-matching-prefix.outputs.test-results-file-path }}', 'utf8'); const expectedPrefix = ''; const expectedComment = { prefixAndBody: `${expectedPrefix}\n${expectedBody}`, @@ -656,8 +666,8 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - base-directory: ${{ env.NO_FAILURES_DIR }} - create-results-file: true # Keep this so we can compare the comment contents to the expected contents + results-file: ${{ env.PASSING_TESTS_JSON }} + report-name: ${{ env.NO_FAILURES_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: true @@ -687,7 +697,7 @@ jobs: const commentId = '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, core, commentId); - const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedBody = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); const expectedPrefix = ''; const expectedComment = { prefixAndBody: `${expectedPrefix}\n${expectedBody}`, @@ -706,8 +716,8 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - base-directory: ${{ env.NO_FAILURES_DIR }} - create-results-file: true # Keep this so we can compare the comment contents to the expected contents + results-file: ${{ env.PASSING_TESTS_JSON }} + report-name: ${{ env.NO_FAILURES_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: false @@ -736,8 +746,8 @@ jobs: const commentId = '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, core, commentId); - const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); - const expectedPrefix = ''; + const expectedBody = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); + const expectedPrefix = ''; const expectedComment = { prefixAndBody: `${expectedPrefix}\n${expectedBody}`, action: 'created' @@ -755,8 +765,8 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - base-directory: ${{ env.TRUNCATE_DIR }} - create-results-file: true # Keep this so we can compare the comment contents to the expected contents + results-file: ${{ env.TRUNCATE_TESTS_JSON }} + report-name: ${{ env.TRUNCATE_FAILURES_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: true @@ -786,7 +796,7 @@ jobs: const commentId = '${{ steps.truncate.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, core, commentId); - const expectedBody = fs.readFileSync('./test-results.md', 'utf8'); + const expectedBody = fs.readFileSync('${{ steps.truncate.outputs.test-results-file-path }}', 'utf8'); const expectedPrefix = ''; const expectedComment = { prefixAndBody: `${expectedPrefix}\nTest results truncated due to character limit. See full report in output. \n${expectedBody}`, diff --git a/README.md b/README.md index 17889b6..423932c 100644 --- a/README.md +++ b/README.md @@ -68,16 +68,17 @@ For failed test runs you can expand each failed test and view more details about ## Inputs -| Parameter | Is Required | Default | Description | -|--------------------------------|-------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `github-token` | true | N/A | Used for the GitHub Checks API. Value is generally: secrets.GITHUB_TOKEN. | -| `results-file` | true | N/A | The json results file generated by jest. | -| `report-name` | false | jest test results | The desired name of the report that is shown on the PR Comment and inside the Status Check. | -| `create-status-check` | false | true | Flag indicating whether a status check with jest test results should be generated. | -| `create-pr-comment` | false | true | Flag indicating whether a PR comment with jest test results should be generated. When `true` the default behavior is to update an existing comment if one exists. | -| `update-comment-if-one-exists` | false | true | When `create-pr-comment` is true, this flag determines whether a new comment is created or if the action updates an existing comment if one is found which is the default behavior. | -| `ignore-test-failures` | false | `false` | When set to true the check status is set to `Neutral` when there are test failures and it will not block pull requests. | -| `timezone` | false | `UTC` | IANA time zone name (e.g. America/Denver) to display dates in. | +| Parameter | Is Required | Default | Description | +|--------------------------------|-------------|--------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `github-token` | true | N/A | Used for the GitHub Checks API. Value is generally: `secrets.GITHUB_TOKEN`. | +| `results-file` | true | N/A | The json results file generated by jest. | +| `report-name` | false | `Jest Test Results` | The desired name of the report that is shown on the PR Comment and inside the Status Check. | +| `create-status-check` | false | `true` | Flag indicating whether a status check with jest test results should be generated. | +| `ignore-test-failures` | false | `false` | If there are test failures, the check's conclusion is set to `neutral` so it will not block pull requests.

*Only applicable when `create-status-check` is true.* | +| `create-pr-comment` | false | `true` | Flag indicating whether a PR comment with jest test results should be generated. When `true` the default behavior is to update an existing comment if one exists. | +| `update-comment-if-one-exists` | false | `true` | This flag determines whether a new comment is created or if the action updates an existing comment (*if one is found*).

*Only applicable when `create-pr-comment` is true.* | +| `comment-identifier` | false | `${{ env.GITHUB-JOB }}-${{ env.GITHUB-ACTION }}` | A unique identifier which will be added to the generated markdown as a comment (*it will not be visible in the PR comment*).

This identifier enables creating then updating separate results comments on the PR if more than one instance of this action is included in a single job. This can be helpful when there are multiple test projects that run separately but are part of the same job.

*Only applicable when `create-pr-comment` is true.* | +| `timezone` | false | `UTC` | IANA time zone name (e.g. America/Denver) to display dates in. | ## Outputs diff --git a/action.yml b/action.yml index f37e991..54320fe 100644 --- a/action.yml +++ b/action.yml @@ -7,7 +7,7 @@ description: | inputs: github-token: - description: 'Token used to interact with the repository. Generally secrets.GITHUB_TOKEN.' + description: 'Token used to interact with the repository. Generally `secrets.GITHUB_TOKEN.`' required: true results-file: description: 'The json test results file output by jest.' @@ -16,22 +16,33 @@ inputs: description: 'The desired name of the report that is shown on the PR Comment and inside the Status Check.' required: true default: Jest Test Results - ignore-test-failures: - description: 'When set to true the status check is set to neutral when there are test failures and it will not block pull requests.' - required: false - default: 'false' create-status-check: description: 'Flag indicating whether a status check with test results should be generated.' required: true default: 'true' + ignore-test-failures: + description: | + If there are test failures, the check's conclusion is set to `neutral` so it will not block pull requests. + *Only applicable when `create-status-check` is true.* + required: false + default: 'false' create-pr-comment: description: 'Flag indicating whether a PR comment with test results should be generated. When `true` the default behavior is to update an existing comment if one exists.' required: true default: 'true' update-comment-if-one-exists: - description: 'When `create-pr-comment` is true, this flag determines whether a new comment is created or if the action updates an existing comment if one is found which is the default behavior.' + description: | + This flag determines whether a new comment is created or if the action updates an existing comment (*if one is found*). + *Only applicable when `create-pr-comment` is true.* required: true default: 'true' + comment-identifier: + description: | + A unique identifier which will be added to the generated markdown as a comment (*it will not be visible in the PR comment*). + This identifier enables creating then updating separate results comments on the PR if more than one instance of this action is included in a single job. + This can be helpful when there are multiple test projects that run separately but are part of the same job. + *Only applicable when `create-pr-comment` is true.* + required: false timezone: description: 'IANA time zone name (e.g. America/Denver) to display dates in. If timezone is not provided, dates will be shown in UTC.' required: false diff --git a/dist/index.js b/dist/index.js index 0425765..c51831f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2397,10 +2397,8 @@ var require_utils2 = __commonJS({ core2.info(`There are no failing tests.`); return false; } - function createResultsFile2(results) { - const jobId = process.env.GITHUB_JOB || ''; - const stepId = process.env.GITHUB_ACTION || ''; - const resultsFileName = `test-results-${jobId}-${stepId}.md`; + function createResultsFile2(results, jobAndStep2) { + const resultsFileName = `test-results-${jobAndStep2}.md`; core2.info(` Writing results to ${resultsFileName}`); let resultsFilePath = null; @@ -16651,7 +16649,6 @@ var require_github2 = __commonJS({ 'src/github.js'(exports2, module2) { var core2 = require_core(); var github = require_github(); - var markupPrefix = ''; async function createStatusCheck2(repoToken, markupData, conclusion, reportName2) { core2.info(` Creating Status check for ${reportName2}...`); @@ -16695,7 +16692,7 @@ Creating Status check for ${reportName2}...`); }); return statusCheckId; } - async function lookForExistingComment(octokit) { + async function lookForExistingComment(octokit, markupPrefix) { let commentId = null; await octokit .paginate(octokit.rest.issues.listComments, { @@ -16722,19 +16719,22 @@ Creating Status check for ${reportName2}...`); core2.info(`Finished getting comments for PR #${github.context.payload.pull_request.number}.`); return commentId; } - async function createPrComment2(repoToken, markupData, updateCommentIfOneExists2) { + async function createPrComment2(repoToken, markupData, updateCommentIfOneExists2, commentIdentifier2) { if (github.context.eventName != 'pull_request') { core2.info('This event was not triggered by a pull_request. No comment will be created or updated.'); return; } + const markupPrefix = ``; const octokit = github.getOctokit(repoToken); + let commentIdToReturn; let existingCommentId = null; if (updateCommentIfOneExists2) { core2.info('Checking for existing comment on PR....'); - existingCommentId = await lookForExistingComment(octokit); + existingCommentId = await lookForExistingComment(octokit, markupPrefix); } if (existingCommentId) { core2.info(`Updating existing PR #${existingCommentId} comment...`); + commentIdToReturn = existingCommentId; await octokit.rest.issues .updateComment({ owner: github.context.repo.owner, @@ -16761,11 +16761,13 @@ ${markupData}`, }) .then(response => { core2.info(`PR comment was created. ID: ${response.data.id}.`); + commentIdToReturn = response.data.id; }) .catch(error => { core2.setFailed(`An error occurred trying to create the PR comment: ${error.message}`); }); } + return commentIdToReturn; } module2.exports = { createStatusCheck: createStatusCheck2, @@ -19807,6 +19809,8 @@ var shouldCreateStatusCheck = core.getBooleanInput('create-status-check'); var shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); var updateCommentIfOneExists = core.getBooleanInput('update-comment-if-one-exists'); var reportName = core.getInput('report-name'); +var jobAndStep = `${process.env.GITHUB_ACTION}-${process.env.GITHUB_JOB}`; +var commentIdentifier = core.getInput('comment-identifier') || jobAndStep; async function run() { try { const resultsJson = await readJsonResultsFromFile(resultsFile); @@ -19816,8 +19820,8 @@ async function run() { } const failingTestsFound = areThereAnyFailingTests(resultsJson); core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); - const markupData = getMarkupForJson(resultsJson, reportName); - const resultsFilePath = createResultsFile(markupData); + let markupData = getMarkupForJson(resultsJson, reportName); + const resultsFilePath = createResultsFile(markupData, jobAndStep); core.setOutput('test-results-file-path', resultsFilePath); if (shouldCreateStatusCheck) { let conclusion = 'success'; @@ -19828,7 +19832,21 @@ async function run() { core.setOutput('status-check-id', checkId); } if (shouldCreatePRComment) { - await createPrComment(token, markupData, updateCommentIfOneExists); + core.info(` +Creating a PR comment with length ${markupData.length}...`); + const charLimit = 65535; + let truncated = false; + if (markupData.length > charLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${markupData.length}/${charLimit}`; + core.info(message); + truncated = true; + const truncatedMessage = `Test results truncated due to character limit. See full report in output.`; + markupData = `${truncatedMessage} +${markupData.substring(0, charLimit - 100)}`; + } + core.setOutput('test-results-truncated', truncated); + const commentId = await createPrComment(token, markupData, updateCommentIfOneExists, commentIdentifier); + core.setOutput('pr-comment-id', commentId); } } catch (error) { if (error instanceof RangeError) { diff --git a/src/github.js b/src/github.js index 5660cb3..ca2f551 100644 --- a/src/github.js +++ b/src/github.js @@ -1,6 +1,5 @@ const core = require('@actions/core'); const github = require('@actions/github'); -const markupPrefix = ''; async function createStatusCheck(repoToken, markupData, conclusion, reportName) { core.info(`\nCreating Status check for ${reportName}...`); @@ -48,7 +47,7 @@ async function createStatusCheck(repoToken, markupData, conclusion, reportName) return statusCheckId; } -async function lookForExistingComment(octokit) { +async function lookForExistingComment(octokit, markupPrefix) { let commentId = null; await octokit @@ -79,22 +78,25 @@ async function lookForExistingComment(octokit) { return commentId; } -async function createPrComment(repoToken, markupData, updateCommentIfOneExists) { +async function createPrComment(repoToken, markupData, updateCommentIfOneExists, commentIdentifier) { if (github.context.eventName != 'pull_request') { core.info('This event was not triggered by a pull_request. No comment will be created or updated.'); return; } + const markupPrefix = ``; const octokit = github.getOctokit(repoToken); + let commentIdToReturn; let existingCommentId = null; if (updateCommentIfOneExists) { core.info('Checking for existing comment on PR....'); - existingCommentId = await lookForExistingComment(octokit); + existingCommentId = await lookForExistingComment(octokit, markupPrefix); } if (existingCommentId) { core.info(`Updating existing PR #${existingCommentId} comment...`); + commentIdToReturn = existingCommentId; await octokit.rest.issues .updateComment({ @@ -120,11 +122,13 @@ async function createPrComment(repoToken, markupData, updateCommentIfOneExists) }) .then(response => { core.info(`PR comment was created. ID: ${response.data.id}.`); + commentIdToReturn = response.data.id; }) .catch(error => { core.setFailed(`An error occurred trying to create the PR comment: ${error.message}`); }); } + return commentIdToReturn; } module.exports = { diff --git a/src/main.js b/src/main.js index 6fb4e94..40b4460 100644 --- a/src/main.js +++ b/src/main.js @@ -17,6 +17,9 @@ const shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); const updateCommentIfOneExists = core.getBooleanInput('update-comment-if-one-exists'); const reportName = core.getInput('report-name'); +const jobAndStep = `${process.env.GITHUB_ACTION}-${process.env.GITHUB_JOB}`; +const commentIdentifier = core.getInput('comment-identifier') || jobAndStep; + async function run() { try { const resultsJson = await readJsonResultsFromFile(resultsFile); @@ -28,10 +31,10 @@ async function run() { const failingTestsFound = areThereAnyFailingTests(resultsJson); core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); - const markupData = getMarkupForJson(resultsJson, reportName); + let markupData = getMarkupForJson(resultsJson, reportName); // Create this automatically to facilitate testing - const resultsFilePath = createResultsFile(markupData); + const resultsFilePath = createResultsFile(markupData, jobAndStep); core.setOutput('test-results-file-path', resultsFilePath); if (shouldCreateStatusCheck) { @@ -44,9 +47,23 @@ async function run() { } if (shouldCreatePRComment) { + core.info(`\nCreating a PR comment with length ${markupData.length}...`); + // GitHub API has a limit of 65535 characters for a comment so truncate the markup if we need to + const charLimit = 65535; + let truncated = false; + if (markupData.length > charLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${markupData.length}/${charLimit}`; + core.info(message); + + truncated = true; + const truncatedMessage = `Test results truncated due to character limit. See full report in output.`; + markupData = `${truncatedMessage}\n${markupData.substring(0, charLimit - 100)}`; + } + core.setOutput('test-results-truncated', truncated); - await createPrComment(token, markupData, updateCommentIfOneExists); + const commentId = await createPrComment(token, markupData, updateCommentIfOneExists, commentIdentifier); + core.setOutput('pr-comment-id', commentId); // This is mainly for testing purposes } } catch (error) { if (error instanceof RangeError) { diff --git a/src/utils.js b/src/utils.js index 088374c..c0075f0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,10 +31,8 @@ function areThereAnyFailingTests(json) { return false; } -function createResultsFile(results) { - const jobId = process.env.GITHUB_JOB || ''; - const stepId = process.env.GITHUB_ACTION || ''; - const resultsFileName = `test-results-${jobId}-${stepId}.md`; +function createResultsFile(results, jobAndStep) { + const resultsFileName = `test-results-${jobAndStep}.md`; core.info(`\nWriting results to ${resultsFileName}`); let resultsFilePath = null; diff --git a/test/files/truncate.json b/test/files/truncate.json new file mode 100644 index 0000000..bf70831 --- /dev/null +++ b/test/files/truncate.json @@ -0,0 +1,242 @@ +{ + "numFailedTestSuites": 1, + "numFailedTests": 1, + "numPassedTestSuites": 0, + "numPassedTests": 5, + "numPendingTestSuites": 0, + "numPendingTests": 0, + "numRuntimeErrorTestSuites": 0, + "numTodoTests": 0, + "numTotalTestSuites": 1, + "numTotalTests": 6, + "startTime": 1708721075369, + "success": false, + "testResults": [ + { + "assertionResults": [ + { + "status": "failed", + "fullName": "should be able to test failure with long messages 1", + "title": "should be able to test failure with long messages 1", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 2", + "title": "should be able to test failure with long messages 2", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 3", + "title": "should be able to test failure with long messages 3", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 4", + "title": "should be able to test failure with long messages 4", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 5", + "title": "should be able to test failure with long messages 5", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 6", + "title": "should be able to test failure with long messages 6", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 7", + "title": "should be able to test failure with long messages 7", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 8", + "title": "should be able to test failure with long messages 8", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 9", + "title": "should be able to test failure with long messages 9", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 10", + "title": "should be able to test failure with long messages 10", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 11", + "title": "should be able to test failure with long messages 11", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 12", + "title": "should be able to test failure with long messages 12", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 13", + "title": "should be able to test failure with long messages 13", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 14", + "title": "should be able to test failure with long messages 14", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 15", + "title": "should be able to test failure with long messages 15", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 16", + "title": "should be able to test failure with long messages 16", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 17", + "title": "should be able to test failure with long messages 17", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 18", + "title": "should be able to test failure with long messages 18", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 19", + "title": "should be able to test failure with long messages 19", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + }, + { + "status": "failed", + "fullName": "should be able to test failure with long messages 20", + "title": "should be able to test failure with long messages 20", + "failureMessages": [ + "This is a made up reason that is going to be extremely long. It needs to be very long because we want to trigger the truncation. Without long results it will be difficult to test this without repeating the failure a ton of times. I'd rather just have a few of them that are really really long. I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit. You would think a regular stacktrace would be sufficient to make it very long.", + "Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh", + "Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar" + ], + "location": "This is the location of the failure." + } + ], + "endTime": 1708721079273 + } + ], + "wasInterrupted": false +} \ No newline at end of file From 4c1ce039449139d8e8c6cec49578ad80450a79b4 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Mon, 26 Feb 2024 16:49:09 -0700 Subject: [PATCH 07/14] ARCH-2011 - Re-work the expected PR comment assertions & add expected file for truncated scenarios --- .github/workflows/build-and-review-pr.yml | 104 +++++--- test/assert-pr-comment-exists.js | 9 +- .../assert-pr-comment-matches-expectations.js | 59 +++- test/assert-status-check-exists.js | 6 +- ...ssert-status-check-matches-expectations.js | 18 +- test/delete-pr-comment.js | 6 +- test/delete-pre-existing-comments.js | 66 +++++ test/files/expected-pr-comment-truncated.md | 252 ++++++++++++++++++ test/files/expected-pr-comment.md | 49 ++++ test/files/truncate.json | 114 +------- test/update-failing-status-check.js | 10 +- 11 files changed, 508 insertions(+), 185 deletions(-) create mode 100644 test/delete-pre-existing-comments.js create mode 100644 test/files/expected-pr-comment-truncated.md create mode 100644 test/files/expected-pr-comment.md diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index 69197e6..76ebf8a 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -419,7 +419,7 @@ jobs: const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.no-failures.outputs.status-check-id }}'; - const actualCheck = await assertStatusCheckExists(github, core, checkId); + const actualCheck = await assertStatusCheckExists(github, context, core, checkId); const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { @@ -470,7 +470,7 @@ jobs: const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.ignore-failures.outputs.status-check-id }}'; - const actualCheck = await assertStatusCheckExists(github, core, checkId); + const actualCheck = await assertStatusCheckExists(github, context, core, checkId); const expectedBody = fs.readFileSync('${{ env.IGNORE_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { @@ -521,7 +521,7 @@ jobs: const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js'); const checkId = '${{ steps.allow-failures.outputs.status-check-id }}'; - const actualCheck = await assertStatusCheckExists(github, core, checkId); + const actualCheck = await assertStatusCheckExists(github, context, core, checkId); const expectedBody = fs.readFileSync('${{ env.ALLOW_FAILURES_MD_FILE }}', 'utf8'); const expectedValues = { @@ -546,7 +546,7 @@ jobs: const fs = require('fs'); const updateFailingStatusCheck = require('./test/update-failing-status-check.js'); - await updateFailingStatusCheck(github, core, '${{ steps.allow-failures.outputs.status-check-id }}'); + await updateFailingStatusCheck(github, context, core, '${{ steps.allow-failures.outputs.status-check-id }}'); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -560,14 +560,13 @@ jobs: TRUNCATE_TESTS_JSON: './test/files/truncate.json' PASSING_TESTS_JSON: './test/files/passing.json' - NO_FAILURES_MD_FILE: './test/files/expected-check-results-no-failures.md' - IGNORE_FAILURES_MD_FILE: './test/files/expected-check-results-ignore-failures.md' - ALLOW_FAILURES_MD_FILE: './test/files/expected-check-results-allow-failures.md' - - NO_FAILURES_REPORT_NAME: 'No Failures Scenario' - TRUNCATE_FAILURES_REPORT_NAME: 'Truncate Failures Scenario' - + NO_FAILURES_MD_FILE: './test/files/expected-pr-comment.md' + TRUNCATE_MD_FILE: './test/files/expected-pr-comment-truncated.md' + UPDATE_WITH_MATCHING_PREFIX_REPORT_NAME: 'Update Comment with Matching Prefix Scenario' + UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME: 'Update Comment but no Matching Prefix Scenario' + NO_UPDATE_REPORT_NAME: 'Do Not Update Comment Scenario' + TRUNCATE_FAILURES_REPORT_NAME: 'Truncate Failures for PR Comment Scenario' steps: - name: '-------------------------------------------------------------------------------------------------------------' @@ -585,19 +584,27 @@ jobs: - name: Setup - Checkout the action uses: actions/checkout@v4 - - name: Setup - Create a comment that can be updated + - name: Setup - Delete pre-existing process-jest-test-results PR Comments + if: always() + uses: actions/github-script@v7 + with: + script: | + const deletePrComments = require('./test/delete-pre-existing-comments.js'); + await deletePrComments(github, context, core); + + - name: Setup - Create a process-jest-test-results comment that can be updated if: always() uses: actions/github-script@v7 with: script: | - const commentIdentifier = '${{ env.GITHUB_JOB }}-${{ env.GITHUB_ACTION }}'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `\nThis comment will be replaced soon.` + body: `\nThis comment will be replaced soon.` }) .then(response => { + core.info(`The 'existing' process-jest-test-results comment has id: ${response.data.id}`); core.exportVariable('EXISTING_COMMENT_ID', response.data.id); }) .catch(error => { @@ -617,7 +624,7 @@ jobs: with: github-token: '${{ secrets.GITHUB_TOKEN }}' results-file: ${{ env.PASSING_TESTS_JSON }} - report-name: ${{ env.NO_FAILURES_REPORT_NAME }} + report-name: ${{ env.UPDATE_WITH_MATCHING_PREFIX_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: true @@ -645,13 +652,17 @@ jobs: const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); const commentId = '${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}'; - const actualComment = await assertCommentExists(github, core, commentId); + const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ steps.update-with-matching-prefix.outputs.test-results-file-path }}', 'utf8'); - const expectedPrefix = ''; + const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); + const testResultsBody = fs.readFileSync('${{ steps.update-with-matching-prefix.outputs.test-results-file-path }}', 'utf8'); + const expectedComment = { - prefixAndBody: `${expectedPrefix}\n${expectedBody}`, - action: 'updated' + expectedPrefix: '', + expectedBody: expectedBody, + actualTestResults: testResultsBody, + action: 'updated', + truncated: false }; assertCommentMatchesExpectations(core, actualComment, expectedComment); @@ -667,7 +678,7 @@ jobs: with: github-token: '${{ secrets.GITHUB_TOKEN }}' results-file: ${{ env.PASSING_TESTS_JSON }} - report-name: ${{ env.NO_FAILURES_REPORT_NAME }} + report-name: ${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: true @@ -695,13 +706,17 @@ jobs: const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); const commentId = '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'; - const actualComment = await assertCommentExists(github, core, commentId); + const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); - const expectedPrefix = ''; + const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); + const testResultsBody = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); + const expectedComment = { - prefixAndBody: `${expectedPrefix}\n${expectedBody}`, - action: 'created' + expectedPrefix: '', + expectedBody: expectedBody, + actualTestResults: testResultsBody, + action: 'created', + truncated: false }; assertCommentMatchesExpectations(core, actualComment, expectedComment); @@ -717,7 +732,7 @@ jobs: with: github-token: '${{ secrets.GITHUB_TOKEN }}' results-file: ${{ env.PASSING_TESTS_JSON }} - report-name: ${{ env.NO_FAILURES_REPORT_NAME }} + report-name: ${{ env.NO_UPDATE_REPORT_NAME }} create-status-check: false create-pr-comment: true update-comment-if-one-exists: false @@ -744,13 +759,17 @@ jobs: const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); const commentId = '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'; - const actualComment = await assertCommentExists(github, core, commentId); + const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); - const expectedPrefix = ''; + const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); + const testResultsBody = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); + const expectedComment = { - prefixAndBody: `${expectedPrefix}\n${expectedBody}`, - action: 'created' + expectedPrefix: '', + expectedBody: expectedBody, + actualTestResults: testResultsBody, + action: 'created', + truncated: false }; assertCommentMatchesExpectations(core, actualComment, expectedComment); @@ -794,15 +813,18 @@ jobs: const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js'); const commentId = '${{ steps.truncate.outputs.pr-comment-id }}'; - const actualComment = await assertCommentExists(github, core, commentId); + const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ steps.truncate.outputs.test-results-file-path }}', 'utf8'); - const expectedPrefix = ''; + const expectedBody = fs.readFileSync('${{ env.TRUNCATE_MD_FILE }}', 'utf8'); + const testResultsBody = fs.readFileSync('${{ steps.truncate.outputs.test-results-file-path }}', 'utf8'); + const expectedComment = { - prefixAndBody: `${expectedPrefix}\nTest results truncated due to character limit. See full report in output. \n${expectedBody}`, - action: 'updated' + expectedPrefix: '\nTest results truncated due to character limit. See full report in output.\n', + expectedBody: expectedBody, + actualTestResults: testResultsBody, + action: 'updated', + truncated: true }; - assertCommentMatchesExpectations(core, actualComment, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' @@ -818,9 +840,9 @@ jobs: const fs = require('fs'); const deletePrComment = require('./test/delete-pr-comment.js'); - await deletePrComment(github, core, '${{ env.EXISTING_COMMENT_ID }}'); - await deletePrComment(github, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'); - await deletePrComment(github, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'); + //await deletePrComment(github, context, core, '${{ env.EXISTING_COMMENT_ID }}'); + //await deletePrComment(github, context, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'); + //await deletePrComment(github, context, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" \ No newline at end of file diff --git a/test/assert-pr-comment-exists.js b/test/assert-pr-comment-exists.js index d15614b..f01d1ca 100644 --- a/test/assert-pr-comment-exists.js +++ b/test/assert-pr-comment-exists.js @@ -1,4 +1,4 @@ -module.exports = async (github, core, commentId) => { +module.exports = async (github, context, core, commentId) => { core.info(`\nAsserting that PR Comment with the following id exists: '${commentId}'`); let actualComment; @@ -8,8 +8,8 @@ module.exports = async (github, core, commentId) => { } const commentResponse = await github.rest.issues.getComment({ - owner: 'im-open', - repo: 'process-jest-test-results', + owner: context.repo.owner, + repo: context.repo.repo, comment_id: commentId.trim() }); @@ -26,8 +26,9 @@ module.exports = async (github, core, commentId) => { updatedAt: rawComment.updated_at, issueUrl: rawComment.issue_url }; - core.info(`Comment ${actualComment.id} details:`); + core.startGroup(`Comment ${actualComment.id} details:`); console.log(actualComment); + core.endGroup(); } return actualComment; diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index 886c603..3288c47 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -1,4 +1,25 @@ module.exports = async (core, comment, expectedValues) => { + function assertLengthsAreTheSame(prCommentLength, testResultsMdLength) { + core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); + core.info(`\ttest-results.md length: '${testResultsMdLength}'`); + + if (prCommentLength != testResultsMdLength) { + core.setFailed(`\tThe lengths do not match, which is not expected.`); + } else { + core.info(`\tThe lengths match, which is expected.`); + } + } + function assertLengthsAreNotTheSame(prCommentLength, testResultsMdLength) { + core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); + core.info(`\ttest-results.md length: '${testResultsMdLength}'`); + + if (prCommentLength != testResultsMdLength) { + core.info(`\tThe lengths do not match, which is expected.`); + } else { + core.setFailed(`\tThe lengths match, which is not expected.`); + } + } + function assertCreatedAndUpdatedMatch(created, updated) { core.info(`\n\tCreated: '${created}'`); core.info(`\tUpdated: '${updated}'`); @@ -21,24 +42,45 @@ module.exports = async (core, comment, expectedValues) => { } } - function assertValueContainsSubstring(variableName, value, substring) { - core.startGroup(`\n\tChecking ${variableName} contains the substring.`); + function assertValueContainsSubstring(valueName, value, substringName, substring) { if (value.includes(substring)) { - core.info(`\tThe ${variableName} string contains the substring.`); + core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); + core.info(`\tThe ${valueName} string contains the substring.`); } else { - core.setFailed(`\tThe ${variableName} string does not contain the substring.`); - core.info(`\n\tExpected ${variableName}: '${value}'`); - core.info(`\tActual ${variableName}: '${substring}'`); + core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); + core.setFailed(`\tThe ${valueName} string does not contain the ${substringName} substring.`); + core.startGroup('\tString and substring Details'); + core.info(`\n\t${valueName}: '${value}'`); + core.info(`\t${substringName}: '${substring}'`); + core.endGroup(); } - core.endGroup(); } function validateProps() { core.info(`\nAsserting that PR Comment properties match the expected values.`); core.info(`Comment ID: ${comment.id}`); - assertValueContainsSubstring('Body', expectedValues['prefixAndBody'], comment.body); + const expectedPrefix = expectedValues.expectedPrefix; + const expectedBody = expectedValues.expectedBody; + const actualTestResultsMd = expectedValues.actualTestResults; + const actualTestResultsMdWithPrefix = `${expectedPrefix}\n${actualTestResultsMd}`; + const actualComment = comment.body; + + // The actual comment body should contain the expected prefix and the expected body + assertValueContainsSubstring('PR Comment', actualComment, 'Expected Prefix', expectedPrefix); + assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedBody); + + // The test-results.md file is the whole markdown before truncation so + // it should contain the substring of the actual comment + assertValueContainsSubstring('test-results.md', actualTestResultsMdWithPrefix, 'Actual Comment Body', actualComment); + + if (expectedValues.truncated) { + assertLengthsAreNotTheSame(actualComment.length, actualTestResultsMdWithPrefix.length); + } else { + assertLengthsAreTheSame(actualComment.length, actualTestResultsMdWithPrefix.length); + } + // Doublecheck the timestamps are generally what we expected based on created/updated status switch (expectedValues.action) { case 'updated': assertUpdatedIsAfterCreated(comment.createdAt, comment.updatedAt); @@ -53,5 +95,4 @@ module.exports = async (core, comment, expectedValues) => { } validateProps(); - await new Promise(r => setTimeout(r, 5 * 1000)); }; diff --git a/test/assert-status-check-exists.js b/test/assert-status-check-exists.js index b3172ae..3fb16cc 100644 --- a/test/assert-status-check-exists.js +++ b/test/assert-status-check-exists.js @@ -1,4 +1,4 @@ -module.exports = async (github, core, statusCheckId) => { +module.exports = async (github, context, core, statusCheckId) => { core.info(`\nAsserting that status check '${statusCheckId} exists`); if (!statusCheckId || statusCheckId.trim() === '') { @@ -9,8 +9,8 @@ module.exports = async (github, core, statusCheckId) => { let statusCheckToReturn; await github.rest.checks .get({ - owner: 'im-open', - repo: 'process-jest-test-results', + owner: context.repo.owner, + repo: context.repo.repo, check_run_id: statusCheckId.trim() }) .then(checkResponse => { diff --git a/test/assert-status-check-matches-expectations.js b/test/assert-status-check-matches-expectations.js index d5a7fc5..cb5cbb1 100644 --- a/test/assert-status-check-matches-expectations.js +++ b/test/assert-status-check-matches-expectations.js @@ -10,16 +10,18 @@ module.exports = async (core, statusCheck, expectedValues) => { } } - function assertValueContainsSubstring(variableName, value, substring) { - core.startGroup(`\tChecking ${variableName} contains the substring.`); + function assertValueContainsSubstring(valueName, value, substringName, substring) { if (value.includes(substring)) { - core.info(`\tThe ${variableName} string contains the substring.`); + core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); + core.info(`\tThe ${valueName} string contains the substring.`); } else { - core.setFailed(`\tThe ${variableName} string does not contain the substring.`); - core.info(`\n\tExpected ${variableName}: '${value}'`); - core.info(`\tActual ${variableName}: '${substring}'`); + core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); + core.setFailed(`\tThe ${valueName} string does not contain the ${substringName} substring.`); + core.startGroup('\tString and substring Details'); + core.info(`\n\t${valueName}: '${value}'`); + core.info(`\t${substringName}: '${substring}'`); + core.endGroup(); } - core.endGroup(); } function validateProps() { @@ -34,7 +36,7 @@ module.exports = async (core, statusCheck, expectedValues) => { // The summary should be something like: 'This test run completed at `Wed, 21 Feb 2024 20:21:48 GMT`' // so just check that it contains the static portion. - assertValueContainsSubstring('Summary', statusCheck.summary, 'This test run completed at `'); + assertValueContainsSubstring('Summary', statusCheck.summary, 'Partial Test Run Text', 'This test run completed at `'); } validateProps(); diff --git a/test/delete-pr-comment.js b/test/delete-pr-comment.js index 4cbe121..59f6915 100644 --- a/test/delete-pr-comment.js +++ b/test/delete-pr-comment.js @@ -1,4 +1,4 @@ -module.exports = async (github, core, commentId) => { +module.exports = async (github, context, core, commentId) => { core.info(`\nDeleting comment '${commentId}'`); if (!commentId) { @@ -7,8 +7,8 @@ module.exports = async (github, core, commentId) => { await github .request(`DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}`, { - owner: 'im-open', - repo: 'process-jest-test-results', + owner: context.repo.owner, + repo: context.repo.repo, comment_id: commentId, headers: { 'X-GitHub-Api-Version': '2022-11-28' diff --git a/test/delete-pre-existing-comments.js b/test/delete-pre-existing-comments.js new file mode 100644 index 0000000..6e94b48 --- /dev/null +++ b/test/delete-pre-existing-comments.js @@ -0,0 +1,66 @@ +module.exports = async (github, context, core) => { + async function lookForExistingComments(github, context, core, prNum) { + const markupPrefix = `', - expectedBody: expectedBody, - actualTestResults: testResultsBody, + prefix: '', + fullMarkdown: expectedMarkdown, action: 'updated', truncated: false }; - assertCommentMatchesExpectations(core, actualComment, expectedComment); + assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -677,7 +685,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.PASSING_TESTS_JSON }} + results-file: ${{ env.PASSING_JSON_RESULTS_FILE }} report-name: ${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME }} create-status-check: false create-pr-comment: true @@ -708,17 +716,16 @@ jobs: const commentId = '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); - const testResultsBody = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); + const expectedMarkdown = fs.readFileSync('${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_MD_FILE }}', 'utf8'); + const actualTestResults = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); const expectedComment = { - expectedPrefix: '', - expectedBody: expectedBody, - actualTestResults: testResultsBody, + prefix: '', + fullMarkdown: expectedMarkdown, action: 'created', truncated: false }; - assertCommentMatchesExpectations(core, actualComment, expectedComment); + assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -731,7 +738,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.PASSING_TESTS_JSON }} + results-file: ${{ env.PASSING_JSON_RESULTS_FILE }} report-name: ${{ env.NO_UPDATE_REPORT_NAME }} create-status-check: false create-pr-comment: true @@ -761,17 +768,16 @@ jobs: const commentId = '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8'); - const testResultsBody = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); + const expectedMarkdown = fs.readFileSync('${{ env.NO_UPDATE_MD_FILE }}', 'utf8'); + const actualTestResults = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); const expectedComment = { - expectedPrefix: '', - expectedBody: expectedBody, - actualTestResults: testResultsBody, + prefix: ``, + fullMarkdown: expectedMarkdown, action: 'created', truncated: false }; - assertCommentMatchesExpectations(core, actualComment, expectedComment); + assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -784,7 +790,7 @@ jobs: uses: ./ with: github-token: '${{ secrets.GITHUB_TOKEN }}' - results-file: ${{ env.TRUNCATE_TESTS_JSON }} + results-file: ${{ env.TRUNCATE_JSON_RESULTS_FILE }} report-name: ${{ env.TRUNCATE_FAILURES_REPORT_NAME }} create-status-check: false create-pr-comment: true @@ -815,17 +821,19 @@ jobs: const commentId = '${{ steps.truncate.outputs.pr-comment-id }}'; const actualComment = await assertCommentExists(github, context, core, commentId); - const expectedBody = fs.readFileSync('${{ env.TRUNCATE_MD_FILE }}', 'utf8'); - const testResultsBody = fs.readFileSync('${{ steps.truncate.outputs.test-results-file-path }}', 'utf8'); - + const expectedMarkdown = fs.readFileSync('${{ env.TRUNCATE_FULL_MD_FILE }}', 'utf8'); + const expectedTruncatedMarkdown = fs.readFileSync('${{ env.TRUNCATE_TRUNCATED_MD_FILE }}', 'utf8'); + const actualTestResults = fs.readFileSync('${{ steps.truncate.outputs.test-results-file-path }}', 'utf8'); + const truncateMessage = 'Test results truncated due to character limit. See full report in output.'; + const expectedComment = { - expectedPrefix: '\nTest results truncated due to character limit. See full report in output.\n', - expectedBody: expectedBody, - actualTestResults: testResultsBody, + prefix: ``, + fullMarkdown: expectedMarkdown, action: 'updated', - truncated: true + truncated: true, + truncatedMarkdown: expectedTruncatedMarkdown, }; - assertCommentMatchesExpectations(core, actualComment, expectedComment); + assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" diff --git a/README.md b/README.md index 423932c..f74b57c 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ For failed test runs you can expand each failed test and view more details about | `ignore-test-failures` | false | `false` | If there are test failures, the check's conclusion is set to `neutral` so it will not block pull requests.

*Only applicable when `create-status-check` is true.* | | `create-pr-comment` | false | `true` | Flag indicating whether a PR comment with jest test results should be generated. When `true` the default behavior is to update an existing comment if one exists. | | `update-comment-if-one-exists` | false | `true` | This flag determines whether a new comment is created or if the action updates an existing comment (*if one is found*).

*Only applicable when `create-pr-comment` is true.* | -| `comment-identifier` | false | `${{ env.GITHUB-JOB }}-${{ env.GITHUB-ACTION }}` | A unique identifier which will be added to the generated markdown as a comment (*it will not be visible in the PR comment*).

This identifier enables creating then updating separate results comments on the PR if more than one instance of this action is included in a single job. This can be helpful when there are multiple test projects that run separately but are part of the same job.

*Only applicable when `create-pr-comment` is true.* | +| `comment-identifier` | false | `${{ env.GITHUB-JOB }}_${{ env.GITHUB-ACTION }}` | A unique identifier which will be added to the generated markdown as a comment (*it will not be visible in the PR comment*).

This identifier enables creating then updating separate results comments on the PR if more than one instance of this action is included in a single job. This can be helpful when there are multiple test projects that run separately but are part of the same job.

*Only applicable when `create-pr-comment` is true.* | | `timezone` | false | `UTC` | IANA time zone name (e.g. America/Denver) to display dates in. | ## Outputs diff --git a/action.yml b/action.yml index 54320fe..7d87047 100644 --- a/action.yml +++ b/action.yml @@ -41,6 +41,7 @@ inputs: A unique identifier which will be added to the generated markdown as a comment (*it will not be visible in the PR comment*). This identifier enables creating then updating separate results comments on the PR if more than one instance of this action is included in a single job. This can be helpful when there are multiple test projects that run separately but are part of the same job. + Defaults to GITHUB_JOB_GITHUB_ACTION if not provided. *Only applicable when `create-pr-comment` is true.* required: false timezone: diff --git a/dist/index.js b/dist/index.js index c51831f..cad9545 100644 --- a/dist/index.js +++ b/dist/index.js @@ -16719,18 +16719,19 @@ Creating Status check for ${reportName2}...`); core2.info(`Finished getting comments for PR #${github.context.payload.pull_request.number}.`); return commentId; } - async function createPrComment2(repoToken, markupData, updateCommentIfOneExists2, commentIdentifier2) { + async function createPrComment2(repoToken, markdown, updateCommentIfOneExists2, commentIdentifier2) { if (github.context.eventName != 'pull_request') { core2.info('This event was not triggered by a pull_request. No comment will be created or updated.'); return; } - const markupPrefix = ``; + const markdownPrefix = ``; + core2.info(`The markdown prefix will be: '${markdownPrefix}'`); const octokit = github.getOctokit(repoToken); let commentIdToReturn; let existingCommentId = null; if (updateCommentIfOneExists2) { core2.info('Checking for existing comment on PR....'); - existingCommentId = await lookForExistingComment(octokit, markupPrefix); + existingCommentId = await lookForExistingComment(octokit, markdownPrefix); } if (existingCommentId) { core2.info(`Updating existing PR #${existingCommentId} comment...`); @@ -16739,8 +16740,8 @@ Creating Status check for ${reportName2}...`); .updateComment({ owner: github.context.repo.owner, repo: github.context.repo.repo, - body: `${markupPrefix} -${markupData}`, + body: `${markdownPrefix} +${markdown}`, comment_id: existingCommentId }) .then(response => { @@ -16755,8 +16756,8 @@ ${markupData}`, .createComment({ owner: github.context.repo.owner, repo: github.context.repo.repo, - body: `${markupPrefix} -${markupData}`, + body: `${markdownPrefix} +${markdown}`, issue_number: github.context.payload.pull_request.number }) .then(response => { @@ -19809,7 +19810,7 @@ var shouldCreateStatusCheck = core.getBooleanInput('create-status-check'); var shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); var updateCommentIfOneExists = core.getBooleanInput('update-comment-if-one-exists'); var reportName = core.getInput('report-name'); -var jobAndStep = `${process.env.GITHUB_ACTION}-${process.env.GITHUB_JOB}`; +var jobAndStep = `${process.env.GITHUB_JOB}_${process.env.GITHUB_ACTION}`; var commentIdentifier = core.getInput('comment-identifier') || jobAndStep; async function run() { try { @@ -19820,9 +19821,7 @@ async function run() { } const failingTestsFound = areThereAnyFailingTests(resultsJson); core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); - let markupData = getMarkupForJson(resultsJson, reportName); - const resultsFilePath = createResultsFile(markupData, jobAndStep); - core.setOutput('test-results-file-path', resultsFilePath); + const markupData = getMarkupForJson(resultsJson, reportName); if (shouldCreateStatusCheck) { let conclusion = 'success'; if (!resultsJson.success) { @@ -19836,18 +19835,23 @@ async function run() { Creating a PR comment with length ${markupData.length}...`); const charLimit = 65535; let truncated = false; - if (markupData.length > charLimit) { - const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${markupData.length}/${charLimit}`; + let mdForComment = markupData; + if (mdForComment.length > charLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${charLimit}`; core.info(message); truncated = true; - const truncatedMessage = `Test results truncated due to character limit. See full report in output.`; - markupData = `${truncatedMessage} -${markupData.substring(0, charLimit - 100)}`; + const truncatedMessage = `> [!Important] +> Test results truncated due to character limit. See full report in output. +`; + mdForComment = `${truncatedMessage} +${mdForComment.substring(0, charLimit - 100)}`; } core.setOutput('test-results-truncated', truncated); - const commentId = await createPrComment(token, markupData, updateCommentIfOneExists, commentIdentifier); + const commentId = await createPrComment(token, mdForComment, updateCommentIfOneExists, commentIdentifier); core.setOutput('pr-comment-id', commentId); } + const resultsFilePath = createResultsFile(markupData, jobAndStep); + core.setOutput('test-results-file-path', resultsFilePath); } catch (error) { if (error instanceof RangeError) { core.info(error.message); diff --git a/src/github.js b/src/github.js index ca2f551..b1997f1 100644 --- a/src/github.js +++ b/src/github.js @@ -78,20 +78,22 @@ async function lookForExistingComment(octokit, markupPrefix) { return commentId; } -async function createPrComment(repoToken, markupData, updateCommentIfOneExists, commentIdentifier) { +async function createPrComment(repoToken, markdown, updateCommentIfOneExists, commentIdentifier) { if (github.context.eventName != 'pull_request') { core.info('This event was not triggered by a pull_request. No comment will be created or updated.'); return; } - const markupPrefix = ``; + const markdownPrefix = ``; + core.info(`The markdown prefix will be: '${markdownPrefix}'`); + const octokit = github.getOctokit(repoToken); let commentIdToReturn; let existingCommentId = null; if (updateCommentIfOneExists) { core.info('Checking for existing comment on PR....'); - existingCommentId = await lookForExistingComment(octokit, markupPrefix); + existingCommentId = await lookForExistingComment(octokit, markdownPrefix); } if (existingCommentId) { @@ -102,7 +104,7 @@ async function createPrComment(repoToken, markupData, updateCommentIfOneExists, .updateComment({ owner: github.context.repo.owner, repo: github.context.repo.repo, - body: `${markupPrefix}\n${markupData}`, + body: `${markdownPrefix}\n${markdown}`, comment_id: existingCommentId }) .then(response => { @@ -117,7 +119,7 @@ async function createPrComment(repoToken, markupData, updateCommentIfOneExists, .createComment({ owner: github.context.repo.owner, repo: github.context.repo.repo, - body: `${markupPrefix}\n${markupData}`, + body: `${markdownPrefix}\n${markdown}`, issue_number: github.context.payload.pull_request.number }) .then(response => { diff --git a/src/main.js b/src/main.js index 40b4460..7f79c71 100644 --- a/src/main.js +++ b/src/main.js @@ -17,7 +17,7 @@ const shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); const updateCommentIfOneExists = core.getBooleanInput('update-comment-if-one-exists'); const reportName = core.getInput('report-name'); -const jobAndStep = `${process.env.GITHUB_ACTION}-${process.env.GITHUB_JOB}`; +const jobAndStep = `${process.env.GITHUB_JOB}_${process.env.GITHUB_ACTION}`; const commentIdentifier = core.getInput('comment-identifier') || jobAndStep; async function run() { @@ -31,11 +31,7 @@ async function run() { const failingTestsFound = areThereAnyFailingTests(resultsJson); core.setOutput('test-outcome', failingTestsFound ? 'Failed' : 'Passed'); - let markupData = getMarkupForJson(resultsJson, reportName); - - // Create this automatically to facilitate testing - const resultsFilePath = createResultsFile(markupData, jobAndStep); - core.setOutput('test-results-file-path', resultsFilePath); + const markupData = getMarkupForJson(resultsJson, reportName); if (shouldCreateStatusCheck) { let conclusion = 'success'; @@ -52,19 +48,24 @@ async function run() { // GitHub API has a limit of 65535 characters for a comment so truncate the markup if we need to const charLimit = 65535; let truncated = false; - if (markupData.length > charLimit) { - const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${markupData.length}/${charLimit}`; + let mdForComment = markupData; + if (mdForComment.length > charLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${charLimit}`; core.info(message); truncated = true; - const truncatedMessage = `Test results truncated due to character limit. See full report in output.`; - markupData = `${truncatedMessage}\n${markupData.substring(0, charLimit - 100)}`; + const truncatedMessage = `> [!Important]\n> Test results truncated due to character limit. See full report in output.\n`; + mdForComment = `${truncatedMessage}\n${mdForComment.substring(0, charLimit - 100)}`; } core.setOutput('test-results-truncated', truncated); - const commentId = await createPrComment(token, markupData, updateCommentIfOneExists, commentIdentifier); + const commentId = await createPrComment(token, mdForComment, updateCommentIfOneExists, commentIdentifier); core.setOutput('pr-comment-id', commentId); // This is mainly for testing purposes } + + // Create this automatically to facilitate testing + const resultsFilePath = createResultsFile(markupData, jobAndStep); + core.setOutput('test-results-file-path', resultsFilePath); } catch (error) { if (error instanceof RangeError) { core.info(error.message); diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index 3288c47..d2b256e 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -1,4 +1,4 @@ -module.exports = async (core, comment, expectedValues) => { +module.exports = async (core, actualComment, actualTestResults, expectedComment) => { function assertLengthsAreTheSame(prCommentLength, testResultsMdLength) { core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); core.info(`\ttest-results.md length: '${testResultsMdLength}'`); @@ -9,6 +9,7 @@ module.exports = async (core, comment, expectedValues) => { core.info(`\tThe lengths match, which is expected.`); } } + function assertLengthsAreNotTheSame(prCommentLength, testResultsMdLength) { core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); core.info(`\ttest-results.md length: '${testResultsMdLength}'`); @@ -58,38 +59,33 @@ module.exports = async (core, comment, expectedValues) => { function validateProps() { core.info(`\nAsserting that PR Comment properties match the expected values.`); - core.info(`Comment ID: ${comment.id}`); - const expectedPrefix = expectedValues.expectedPrefix; - const expectedBody = expectedValues.expectedBody; - const actualTestResultsMd = expectedValues.actualTestResults; - const actualTestResultsMdWithPrefix = `${expectedPrefix}\n${actualTestResultsMd}`; - const actualComment = comment.body; + const expectedPrefix = expectedComment.prefix; + const expectedFullMd = expectedComment.fullMarkdown; + const expectedTruncatedMd = expectedComment.truncatedMarkdown; + const isTruncated = expectedComment.truncated; - // The actual comment body should contain the expected prefix and the expected body + // Check the actual comment's body assertValueContainsSubstring('PR Comment', actualComment, 'Expected Prefix', expectedPrefix); - assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedBody); - - // The test-results.md file is the whole markdown before truncation so - // it should contain the substring of the actual comment - assertValueContainsSubstring('test-results.md', actualTestResultsMdWithPrefix, 'Actual Comment Body', actualComment); - - if (expectedValues.truncated) { - assertLengthsAreNotTheSame(actualComment.length, actualTestResultsMdWithPrefix.length); + if (isTruncated) { + assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedTruncatedMd); } else { - assertLengthsAreTheSame(actualComment.length, actualTestResultsMdWithPrefix.length); + assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedFullMd); } + // Check the test-results.md file + assertValueContainsSubstring('test-results.md', actualTestResults, 'Expected Body', expectedFullMd); + // Doublecheck the timestamps are generally what we expected based on created/updated status - switch (expectedValues.action) { + switch (expectedComment.action) { case 'updated': - assertUpdatedIsAfterCreated(comment.createdAt, comment.updatedAt); + assertUpdatedIsAfterCreated(actualComment.createdAt, actualComment.updatedAt); break; case 'created': - assertCreatedAndUpdatedMatch(comment.createdAt, comment.updatedAt); + assertCreatedAndUpdatedMatch(actualComment.createdAt, actualComment.updatedAt); break; default: - core.setFailed(`The action '${expectedValues.action}' is not supported.`); + core.setFailed(`The action '${expectedComment.action}' is not supported.`); break; } } diff --git a/test/files/expected-pr-comment.md b/test/expected-markdown/pr-comments/no-update.md similarity index 96% rename from test/files/expected-pr-comment.md rename to test/expected-markdown/pr-comments/no-update.md index 9d4ac5b..1acb3f1 100644 --- a/test/files/expected-pr-comment.md +++ b/test/expected-markdown/pr-comments/no-update.md @@ -1,4 +1,4 @@ -# No Failures for PR Comment Scenario +# Do Not Update Comment Scenario ![Generic badge](https://img.shields.io/badge/6/6-PASSED-brightgreen.svg)
diff --git a/test/expected-markdown/pr-comments/truncate-full-markdown.md b/test/expected-markdown/pr-comments/truncate-full-markdown.md new file mode 100644 index 0000000..4b3217b --- /dev/null +++ b/test/expected-markdown/pr-comments/truncate-full-markdown.md @@ -0,0 +1,279 @@ +# Truncated PR Comment Scenario + +![Generic badge](https://img.shields.io/badge/10/10-FAILED-red.svg) +
+ Duration: 3.904 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:44:35.369 UTC
Finish:2024-02-23 20:44:39.273 UTC
Duration:3.904 seconds
+
+
+ Outcome: Failed | Total Tests: 10 | Passed: 5 | Failed: 10 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:10
Failed Test Suites:1
Failed Tests:10
Passed Test Suites:0
Passed Tests:5
+
+
+ :x: should be able to test failure with long messages 1 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 1
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 2 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 2
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 3 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 3
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 4 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 4
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 5 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 5
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 6 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 6
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 7 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 7
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 8 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 8
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 9 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 9
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
+
+ :x: should be able to test failure with long messages 10 + + + + + + + + + + + + + + + + + +
Title:should be able to test failure with long messages 10
Status:failed
Location:This is the location of the failure.
Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl vel pretium lectus quam id leo in vitae turpis massa sed elementum tempus egestas sed sed risus pretium quam vulputate dignissim suspendisse in est ante in nibh
+Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas sed tempus urna et pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna eget est lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas integer eget aliquet nibh praesent tristique magna sit amet purus gravida quis blandit turpis cursus in hac habitasse platea dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc congue nisi vitae suscipit tellus mauris a diam maecenas sed enim ut sem viverra aliquet eget sit amet tellus cras adipiscing enim eu turpis egestas pretium aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros in cursus turpis massa tincidunt dui ut ornare lectus sit amet est placerat in egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor leo a diam sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam eget felis eget nunc lobortis mattis aliquam faucibus purus in massa tempor nec feugiat nisl pretium fusce id velit ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus in hac habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius duis at consectetur lorem donec massa sapien faucibus et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor eu augue ut lectus arcu bibendum at varius vel pharetra vel turpis nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras semper auctor neque vitae tempus quam pellentesque nec nam aliquam sem et tortor consequat id porta nibh venenatis cras sed felis eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar
+
diff --git a/test/files/expected-pr-comment-truncated.md b/test/expected-markdown/pr-comments/truncate-truncated-markdown.md similarity index 99% rename from test/files/expected-pr-comment-truncated.md rename to test/expected-markdown/pr-comments/truncate-truncated-markdown.md index dc230cd..ac8eb4b 100644 --- a/test/files/expected-pr-comment-truncated.md +++ b/test/expected-markdown/pr-comments/truncate-truncated-markdown.md @@ -1,6 +1,9 @@ -# Truncate Failures for PR Comment Scenario +> [!Important] +> Test results truncated due to character limit. See full report in output. -![Generic badge](https://img.shields.io/badge/1/6-FAILED-red.svg) +# Truncated PR Comment Scenario + +![Generic badge](https://img.shields.io/badge/10/10-FAILED-red.svg)
Duration: 3.904 seconds @@ -19,7 +22,7 @@
- Outcome: Failed | Total Tests: 10 | Passed: 0 | Failed: 10 + Outcome: Failed | Total Tests: 10 | Passed: 5 | Failed: 10 @@ -43,7 +46,7 @@ - +
Total Test Suites:
Passed Tests:05
@@ -249,4 +252,4 @@ Error B: nibh nisl condimentum id venenatis a condimentum vitae sapien pellentes Failure Messages:
This is a made up reason that is going to be extremely long.  It needs to be very long because we want to trigger the truncation.  Without long results it will be difficult to test this without repeating the failure a ton of times.  I'd rather just have a few of them that are really really long.  I could probably add some lorem ipsum text here too to make sure that we're getting lots of text that will max out the 65k character limit.  You would think a regular stacktrace would be sufficient to make it very long.
-Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus pellente
+Error A: faucibus pulvinar elementum integer enim neque volutpat ac tincidunt vitae semper quis lectus nulla at volutpat diam ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin fermentum leo vel orci porta non pulvinar neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam non nisi est sit amet facilisis magna etiam tempor orci eu lobortis elementum nibh tellus molestie nunc non blandit massa enim nec dui nunc mattis enim ut tellus elementum sagittis vitae et leo duis ut diam quam nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit egestas dui id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat interdum varius sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo donec enim diam vulputate ut pharetra sit amet aliquam id diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus turpis in eu mi bibendum neque egestas congue quisque egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat sed cras ornare arcu dui vivamus arcu felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim sit amet venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque massa placerat duis ultricies lacus sed turpis tincidunt id aliquet risus feugiat in ante metus dictum at tempor commodo ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia at quis risus sed vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque in dictum non consectetur a erat nam at lectus urna duis convallis convallis tellus id interdum velit laoreet id donec ultrices tincidunt arcu non sodales neque sodales ut etiam sit amet nisl purus in mollis nunc sed id semper risus in hendrerit gravida rutrum quisque non tellus orci ac auctor augue mauris augue neque gravida in fermentum et sollicitudin ac orci phasellus egestas tellus rutrum tellus
\ No newline at end of file
diff --git a/test/expected-markdown/pr-comments/update-matching-prefix.md b/test/expected-markdown/pr-comments/update-matching-prefix.md
new file mode 100644
index 0000000..5c6885b
--- /dev/null
+++ b/test/expected-markdown/pr-comments/update-matching-prefix.md
@@ -0,0 +1,49 @@
+# Update Comment with Matching Prefix Scenario
+
+![Generic badge](https://img.shields.io/badge/6/6-PASSED-brightgreen.svg)
+
+ Duration: 5.688 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:43:06.979 UTC
Finish:2024-02-23 20:43:12.667 UTC
Duration:5.688 seconds
+
+
+ Outcome: Passed | Total Tests: 6 | Passed: 6 | Failed: 0 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:0
Failed Tests:0
Passed Test Suites:1
Passed Tests:6
+
diff --git a/test/expected-markdown/pr-comments/update-without-matching-prefix.md b/test/expected-markdown/pr-comments/update-without-matching-prefix.md new file mode 100644 index 0000000..5cbdcb4 --- /dev/null +++ b/test/expected-markdown/pr-comments/update-without-matching-prefix.md @@ -0,0 +1,49 @@ +# Update Comment but no Matching Prefix Scenario + +![Generic badge](https://img.shields.io/badge/6/6-PASSED-brightgreen.svg) +
+ Duration: 5.688 seconds + + + + + + + + + + + + + +
Start:2024-02-23 20:43:06.979 UTC
Finish:2024-02-23 20:43:12.667 UTC
Duration:5.688 seconds
+
+
+ Outcome: Passed | Total Tests: 6 | Passed: 6 | Failed: 0 + + + + + + + + + + + + + + + + + + + + + + + + + +
Total Test Suites:1
Total Tests:6
Failed Test Suites:0
Failed Tests:0
Passed Test Suites:1
Passed Tests:6
+
diff --git a/test/files/expected-check-results-allow-failures.md b/test/expected-markdown/status-checks/allow-failures.md similarity index 100% rename from test/files/expected-check-results-allow-failures.md rename to test/expected-markdown/status-checks/allow-failures.md diff --git a/test/files/expected-check-results-ignore-failures.md b/test/expected-markdown/status-checks/ignore-failures.md similarity index 100% rename from test/files/expected-check-results-ignore-failures.md rename to test/expected-markdown/status-checks/ignore-failures.md diff --git a/test/files/expected-check-results-no-failures.md b/test/expected-markdown/status-checks/no-failures.md similarity index 100% rename from test/files/expected-check-results-no-failures.md rename to test/expected-markdown/status-checks/no-failures.md diff --git a/test/files/expected-results-for-failing-tests.md b/test/expected-markdown/unit-tests/failing-tests.md similarity index 100% rename from test/files/expected-results-for-failing-tests.md rename to test/expected-markdown/unit-tests/failing-tests.md diff --git a/test/files/expected-results-for-no-tests.md b/test/expected-markdown/unit-tests/no-tests.md similarity index 100% rename from test/files/expected-results-for-no-tests.md rename to test/expected-markdown/unit-tests/no-tests.md diff --git a/test/files/expected-results-for-passing-tests.md b/test/expected-markdown/unit-tests/passing-tests.md similarity index 100% rename from test/files/expected-results-for-passing-tests.md rename to test/expected-markdown/unit-tests/passing-tests.md diff --git a/test/files/empty-results.json b/test/input-files/empty-results.json similarity index 100% rename from test/files/empty-results.json rename to test/input-files/empty-results.json diff --git a/test/files/failing.json b/test/input-files/failing.json similarity index 100% rename from test/files/failing.json rename to test/input-files/failing.json diff --git a/test/files/no-tests.json b/test/input-files/no-tests.json similarity index 100% rename from test/files/no-tests.json rename to test/input-files/no-tests.json diff --git a/test/files/passing.json b/test/input-files/passing.json similarity index 100% rename from test/files/passing.json rename to test/input-files/passing.json diff --git a/test/files/truncate.json b/test/input-files/truncate.json similarity index 100% rename from test/files/truncate.json rename to test/input-files/truncate.json From 8991a31f1937aa139d1b57a6ac95beb82e3f07fa Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 12:45:02 -0700 Subject: [PATCH 09/14] ARCH-2011 - Put all jobs back in --- .github/workflows/build-and-review-pr.yml | 60 +++++++++---------- .../assert-pr-comment-matches-expectations.js | 6 +- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build-and-review-pr.yml b/.github/workflows/build-and-review-pr.yml index da1c650..970b4e1 100644 --- a/.github/workflows/build-and-review-pr.yml +++ b/.github/workflows/build-and-review-pr.yml @@ -21,18 +21,15 @@ on: # without disabling that requirement. If we have a status check that is always produced, # we can also use that to require all branches be up to date before they are merged. - env: EMPTY_JSON_RESULTS_FILE: './test/input-files/empty-results.json' FAILING_JSON_RESULTS_FILE: './test/input-files/failing.json' NO_TESTS_JSON_RESULTS_FILE: './test/input-files/no-tests.json' PASSING_JSON_RESULTS_FILE: './test/input-files/passing.json' TRUNCATE_JSON_RESULTS_FILE: './test/input-files/truncate.json' - jobs: build-and-review-pr: - if: 1 == 2 # This reusable workflow will check to see if an action's source code has changed based on # whether the PR includes files that match the files-with-code arg or are in one of the # dirs-with-code directories. If there are source code changes, this reusable workflow @@ -70,9 +67,8 @@ jobs: # The npm script to run to build the action. This is typically 'npm run build' if the # action needs to be compiled. For composite-run-steps actions this is typically empty. build-command: 'npm run build' - + unit-tests: - if: 1 == 2 runs-on: ubuntu-latest env: PASSING_MD_FILE: './test/expected-markdown/unit-tests/passing-tests.md' @@ -174,8 +170,7 @@ jobs: ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.file-does-not-exist.outputs.test-results-file-path }}" ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.file-does-not-exist.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.file-does-not-exist.outputs.pr-comment-id }}" - - + - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" - name: ' TEST 4 - RESULTS_FILE IS EMPTY ' @@ -207,7 +202,7 @@ jobs: ./test/assert-value-is-empty.sh --name "test-results-file-path output" --value "${{ steps.empty-file.outputs.test-results-file-path }}" ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.empty-file.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.empty-file.outputs.pr-comment-id }}" - + - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" - name: ' TEST 5 - PASSING TESTS ' @@ -233,7 +228,7 @@ jobs: if: always() run: | ./test/assert-values-match.sh --name "test-outcome output" --expected 'Passed' --actual "${{ steps.passing-tests.outputs.test-outcome }}" - + - name: 5 - And the 'test-results-file-path output' should be populated if: always() run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.passing-tests.outputs.test-results-file-path }}" @@ -244,7 +239,7 @@ jobs: ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.passing-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.passing-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.passing-tests.outputs.test-results-truncated }}" - + - name: 5 - And the contents of test-results.md file should match the contents of ${{ env.PASSING_MD_FILE }} file if: always() run: | @@ -254,7 +249,7 @@ jobs: # - The badge has the right count/status/color # - The Duration stats are included in the report # - The Counter stats are included in the report - + expectedFileName="${{ env.PASSING_MD_FILE }}" actualFileName="${{ steps.passing-tests.outputs.test-results-file-path }}" ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName @@ -284,7 +279,7 @@ jobs: if: always() run: | ./test/assert-values-match.sh --name "test-outcome output" --expected 'Failed' --actual "${{ steps.failing-tests.outputs.test-outcome }}" - + - name: 6 - And the 'test-results-file-path output' should be populated if: always() run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.failing-tests.outputs.test-results-file-path }}" @@ -295,7 +290,7 @@ jobs: ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.failing-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.failing-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.failing-tests.outputs.test-results-truncated }}" - + - name: 6 - And the contents of test-results.md file should match the contents of ${{ env.FAILING_MD_FILE }} file if: always() run: | @@ -310,7 +305,7 @@ jobs: expectedFileName="${{ env.FAILING_MD_FILE }}" actualFileName="${{ steps.failing-tests.outputs.test-results-file-path }}" ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName - + - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" - name: ' TEST 7 - NO TESTS REPORTED ' @@ -326,7 +321,7 @@ jobs: report-name: 'Missing Test Results' create-status-check: false create-pr-comment: false - + - name: 7 - Then the action outcome should be success if: always() run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.no-tests.outcome }}" @@ -335,7 +330,7 @@ jobs: if: always() run: | ./test/assert-values-match.sh --name "test-outcome output" --expected 'Passed' --actual "${{ steps.no-tests.outputs.test-outcome }}" - + - name: 7 - And the 'test-results-file-path output' should be populated if: always() run: ./test/assert-value-is-not-empty.sh --name "test-results-file-path output" --value "${{ steps.no-tests.outputs.test-results-file-path }}" @@ -346,7 +341,7 @@ jobs: ./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.no-tests.outputs.status-check-id }}" ./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.no-tests.outputs.pr-comment-id }}" ./test/assert-value-is-empty.sh --name "test-results-truncated output" --value "${{ steps.no-tests.outputs.test-results-truncated }}" - + - name: 7 - And the contents of test-results.md file should match the contents of ${{ env.NO_TESTS_MD_FILE }} file if: always() run: | @@ -363,17 +358,16 @@ jobs: ./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName test-status-checks: - if: 1 == 2 runs-on: ubuntu-latest env: NO_FAILURES_MD_FILE: './test/expected-markdown/status-checks/no-failures.md' IGNORE_FAILURES_MD_FILE: './test/expected-markdown/status-checks/ignore-failures.md' ALLOW_FAILURES_MD_FILE: './test/expected-markdown/status-checks/allow-failures.md' - + NO_FAILURES_REPORT_NAME: 'No Failures Scenario' IGNORE_FAILURES_REPORT_NAME: 'Ignore Failures Scenario' ALLOW_FAILURES_REPORT_NAME: 'Allow Failures Scenario' - + steps: - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -571,7 +565,7 @@ jobs: NO_UPDATE_MD_FILE: './test/expected-markdown/pr-comments/no-update.md' TRUNCATE_FULL_MD_FILE: './test/expected-markdown/pr-comments/truncate-full-markdown.md' TRUNCATE_TRUNCATED_MD_FILE: './test/expected-markdown/pr-comments/truncate-truncated-markdown.md' - + UPDATE_WITH_MATCHING_PREFIX_REPORT_NAME: 'Update Comment with Matching Prefix Scenario' UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME: 'Update Comment but no Matching Prefix Scenario' NO_UPDATE_REPORT_NAME: 'Do Not Update Comment Scenario' @@ -665,14 +659,14 @@ jobs: const expectedMarkdown = fs.readFileSync('${{ env.UPDATE_WITH_MATCHING_PREFIX_MD_FILE }}', 'utf8'); const actualTestResults = fs.readFileSync('${{ steps.update-with-matching-prefix.outputs.test-results-file-path }}', 'utf8'); - + const expectedComment = { prefix: '', fullMarkdown: expectedMarkdown, action: 'updated', truncated: false }; - assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); + assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -718,14 +712,14 @@ jobs: const expectedMarkdown = fs.readFileSync('${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_MD_FILE }}', 'utf8'); const actualTestResults = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.test-results-file-path }}', 'utf8'); - + const expectedComment = { prefix: '', fullMarkdown: expectedMarkdown, action: 'created', truncated: false }; - assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); + assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -770,14 +764,14 @@ jobs: const expectedMarkdown = fs.readFileSync('${{ env.NO_UPDATE_MD_FILE }}', 'utf8'); const actualTestResults = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.test-results-file-path }}', 'utf8'); - + const expectedComment = { - prefix: ``, + prefix: ``, fullMarkdown: expectedMarkdown, action: 'created', truncated: false }; - assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); + assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -833,7 +827,7 @@ jobs: truncated: true, truncatedMarkdown: expectedTruncatedMarkdown, }; - assertCommentMatchesExpectations(core, actualComment.body, actualTestResults, expectedComment); + assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment); - name: '-------------------------------------------------------------------------------------------------------------' run: echo "" @@ -848,9 +842,9 @@ jobs: const fs = require('fs'); const deletePrComment = require('./test/delete-pr-comment.js'); - //await deletePrComment(github, context, core, '${{ env.EXISTING_COMMENT_ID }}'); - //await deletePrComment(github, context, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'); - //await deletePrComment(github, context, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'); + await deletePrComment(github, context, core, '${{ env.EXISTING_COMMENT_ID }}'); + await deletePrComment(github, context, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}'); + await deletePrComment(github, context, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}'); - name: '-------------------------------------------------------------------------------------------------------------' - run: echo "" \ No newline at end of file + run: echo "" diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index d2b256e..ba2742f 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -66,11 +66,11 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) const isTruncated = expectedComment.truncated; // Check the actual comment's body - assertValueContainsSubstring('PR Comment', actualComment, 'Expected Prefix', expectedPrefix); + assertValueContainsSubstring('PR Comment', actualComment.body, 'Expected Prefix', expectedPrefix); if (isTruncated) { - assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedTruncatedMd); + assertValueContainsSubstring('PR Comment', actualComment.body, 'Expected Body', expectedTruncatedMd); } else { - assertValueContainsSubstring('PR Comment', actualComment, 'Expected Body', expectedFullMd); + assertValueContainsSubstring('PR Comment', actualComment.body, 'Expected Body', expectedFullMd); } // Check the test-results.md file From 51621d6ccfa1d6955100e7894f0dc617ab90be18 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 12:47:30 -0700 Subject: [PATCH 10/14] ARCH-2011 - Update to node20 --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 7d87047..29ef2ad 100644 --- a/action.yml +++ b/action.yml @@ -61,5 +61,5 @@ outputs: description: 'The ID of the PR comment that was created. This is only set if `create-pr-comment` is `true` and a PR was created successfully.' runs: - using: 'node16' + using: 'node20' main: 'dist/index.js' From e8544d2261abc74bd3541c0ee9a4a0f0be7bfd32 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 12:49:23 -0700 Subject: [PATCH 11/14] ARCh-2011 - Update versions in readme.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f74b57c..b3ab029 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ jobs: pull-requests: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: jest test with Coverage continue-on-error: true @@ -128,7 +128,7 @@ jobs: advanced-ci: runs-on: [ubuntu-20.04] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: jest test with results file continue-on-error: true From 62290e63585d865895dd5d41c48972387a22f092 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 12:55:58 -0700 Subject: [PATCH 12/14] ARCH-2011 - Remove unused functions --- .../assert-pr-comment-matches-expectations.js | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index ba2742f..b82efc0 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -1,26 +1,4 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) => { - function assertLengthsAreTheSame(prCommentLength, testResultsMdLength) { - core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); - core.info(`\ttest-results.md length: '${testResultsMdLength}'`); - - if (prCommentLength != testResultsMdLength) { - core.setFailed(`\tThe lengths do not match, which is not expected.`); - } else { - core.info(`\tThe lengths match, which is expected.`); - } - } - - function assertLengthsAreNotTheSame(prCommentLength, testResultsMdLength) { - core.info(`\n\tPR Comment length:\t\t'${prCommentLength}'`); - core.info(`\ttest-results.md length: '${testResultsMdLength}'`); - - if (prCommentLength != testResultsMdLength) { - core.info(`\tThe lengths do not match, which is expected.`); - } else { - core.setFailed(`\tThe lengths match, which is not expected.`); - } - } - function assertCreatedAndUpdatedMatch(created, updated) { core.info(`\n\tCreated: '${created}'`); core.info(`\tUpdated: '${updated}'`); From 61d3cd6a9606e8c6901b4c817644c813e0a812ed Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 14:37:06 -0700 Subject: [PATCH 13/14] Update test/assert-pr-comment-matches-expectations.js Co-authored-by: Joseph Schwartz --- test/assert-pr-comment-matches-expectations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index b82efc0..8a479cd 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -4,7 +4,7 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) core.info(`\tUpdated: '${updated}'`); if (created != updated) { - core.setFailed(`\tThe created and updated dates should match, which is NOT expected.`); + core.setFailed(`\tThe created and updated dates do not match, which is NOT expected.`); } else { core.info(`\tThe created and updated dates match, which is expected.`); } From 954bb4319e04d47990fb36936539d5c67ff54d70 Mon Sep 17 00:00:00 2001 From: Danielle Adams Date: Tue, 27 Feb 2024 16:41:06 -0700 Subject: [PATCH 14/14] ARCH-2011 - Small cleanup items --- dist/index.js | 17 +++++++++-------- src/github.js | 6 +++--- src/main.js | 10 +++++----- src/utils.js | 2 +- test/assert-pr-comment-matches-expectations.js | 17 ++++++++++------- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/dist/index.js b/dist/index.js index cad9545..48e6696 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2389,7 +2389,8 @@ var require_utils2 = __commonJS({ } } function areThereAnyFailingTests2(json) { - core2.info(`Checking for failing tests..`); + core2.info(` +Checking for failing tests..`); if (json.numFailedTests > 0) { core2.warning(`At least one failing test was found.`); return true; @@ -16659,7 +16660,7 @@ Creating Status check for ${reportName2}...`); const status = 'completed'; const checkTime = new Date().toUTCString(); const summary = `This test run completed at \`${checkTime}\``; - let propMessage = ` Name: ${name} + const propMessage = ` Name: ${name} GitSha: ${git_sha} Event: ${github.context.eventName} Status: ${status} @@ -16692,7 +16693,7 @@ Creating Status check for ${reportName2}...`); }); return statusCheckId; } - async function lookForExistingComment(octokit, markupPrefix) { + async function lookForExistingComment(octokit, markdownPrefix) { let commentId = null; await octokit .paginate(octokit.rest.issues.listComments, { @@ -16704,7 +16705,7 @@ Creating Status check for ${reportName2}...`); if (comments.length === 0) { core2.info('There are no comments on the PR. A new comment will be created.'); } else { - const existingComment = comments.find(c => c.body.startsWith(markupPrefix)); + const existingComment = comments.find(c => c.body.startsWith(markdownPrefix)); if (existingComment) { core2.info(`An existing comment (${existingComment.id}) was found and will be updated.`); commentId = existingComment.id; @@ -19833,18 +19834,18 @@ async function run() { if (shouldCreatePRComment) { core.info(` Creating a PR comment with length ${markupData.length}...`); - const charLimit = 65535; + const characterLimit = 65535; let truncated = false; let mdForComment = markupData; - if (mdForComment.length > charLimit) { - const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${charLimit}`; + if (mdForComment.length > characterLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${characterLimit}`; core.info(message); truncated = true; const truncatedMessage = `> [!Important] > Test results truncated due to character limit. See full report in output. `; mdForComment = `${truncatedMessage} -${mdForComment.substring(0, charLimit - 100)}`; +${mdForComment.substring(0, characterLimit - 100)}`; } core.setOutput('test-results-truncated', truncated); const commentId = await createPrComment(token, mdForComment, updateCommentIfOneExists, commentIdentifier); diff --git a/src/github.js b/src/github.js index b1997f1..58a8437 100644 --- a/src/github.js +++ b/src/github.js @@ -12,7 +12,7 @@ async function createStatusCheck(repoToken, markupData, conclusion, reportName) const checkTime = new Date().toUTCString(); const summary = `This test run completed at \`${checkTime}\``; - let propMessage = ` Name: ${name} + const propMessage = ` Name: ${name} GitSha: ${git_sha} Event: ${github.context.eventName} Status: ${status} @@ -47,7 +47,7 @@ async function createStatusCheck(repoToken, markupData, conclusion, reportName) return statusCheckId; } -async function lookForExistingComment(octokit, markupPrefix) { +async function lookForExistingComment(octokit, markdownPrefix) { let commentId = null; await octokit @@ -60,7 +60,7 @@ async function lookForExistingComment(octokit, markupPrefix) { if (comments.length === 0) { core.info('There are no comments on the PR. A new comment will be created.'); } else { - const existingComment = comments.find(c => c.body.startsWith(markupPrefix)); + const existingComment = comments.find(c => c.body.startsWith(markdownPrefix)); if (existingComment) { core.info(`An existing comment (${existingComment.id}) was found and will be updated.`); commentId = existingComment.id; diff --git a/src/main.js b/src/main.js index 7f79c71..2bed891 100644 --- a/src/main.js +++ b/src/main.js @@ -10,7 +10,6 @@ const requiredArgOptions = { const token = core.getInput('github-token', requiredArgOptions); const resultsFile = core.getInput('results-file', requiredArgOptions); - const ignoreTestFailures = core.getBooleanInput('ignore-test-failures'); const shouldCreateStatusCheck = core.getBooleanInput('create-status-check'); const shouldCreatePRComment = core.getBooleanInput('create-pr-comment'); @@ -46,16 +45,17 @@ async function run() { core.info(`\nCreating a PR comment with length ${markupData.length}...`); // GitHub API has a limit of 65535 characters for a comment so truncate the markup if we need to - const charLimit = 65535; + const characterLimit = 65535; let truncated = false; let mdForComment = markupData; - if (mdForComment.length > charLimit) { - const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${charLimit}`; + + if (mdForComment.length > characterLimit) { + const message = `Truncating markup data due to character limit exceeded for GitHub API. Markup data length: ${mdForComment.length}/${characterLimit}`; core.info(message); truncated = true; const truncatedMessage = `> [!Important]\n> Test results truncated due to character limit. See full report in output.\n`; - mdForComment = `${truncatedMessage}\n${mdForComment.substring(0, charLimit - 100)}`; + mdForComment = `${truncatedMessage}\n${mdForComment.substring(0, characterLimit - 100)}`; } core.setOutput('test-results-truncated', truncated); diff --git a/src/utils.js b/src/utils.js index c0075f0..4ac7b35 100644 --- a/src/utils.js +++ b/src/utils.js @@ -20,7 +20,7 @@ async function readJsonResultsFromFile(resultsFile) { } function areThereAnyFailingTests(json) { - core.info(`Checking for failing tests..`); + core.info(`\nChecking for failing tests..`); if (json.numFailedTests > 0) { core.warning(`At least one failing test was found.`); diff --git a/test/assert-pr-comment-matches-expectations.js b/test/assert-pr-comment-matches-expectations.js index 8a479cd..e69436b 100644 --- a/test/assert-pr-comment-matches-expectations.js +++ b/test/assert-pr-comment-matches-expectations.js @@ -1,7 +1,7 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) => { function assertCreatedAndUpdatedMatch(created, updated) { core.info(`\n\tCreated: '${created}'`); - core.info(`\tUpdated: '${updated}'`); + core.info(`\tUpdated: '${updated}'`); if (created != updated) { core.setFailed(`\tThe created and updated dates do not match, which is NOT expected.`); @@ -12,7 +12,7 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) function assertUpdatedIsAfterCreated(created, updated) { core.info(`\n\tCreated: '${created}'`); - core.info(`\tUpdated: '${updated}'`); + core.info(`\tUpdated: '${updated}'`); if (created >= updated) { core.setFailed(`\tThe created date is on or after the updated date, which is NOT expected.`); @@ -24,13 +24,16 @@ module.exports = async (core, actualComment, actualTestResults, expectedComment) function assertValueContainsSubstring(valueName, value, substringName, substring) { if (value.includes(substring)) { core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); - core.info(`\tThe ${valueName} string contains the substring.`); + core.info(`\tThe ${valueName} string contains the substring, which is expected.`); } else { core.info(`\n\tChecking ${valueName} contains the ${substringName} substring.`); - core.setFailed(`\tThe ${valueName} string does not contain the ${substringName} substring.`); - core.startGroup('\tString and substring Details'); - core.info(`\n\t${valueName}: '${value}'`); - core.info(`\t${substringName}: '${substring}'`); + core.setFailed(`\tThe ${valueName} string does not contain the ${substringName} substring, which is not expected.`); + core.startGroup(`\t${valueName} contents:`); + core.info(`'${value}'`); + core.endGroup(); + + core.startGroup(`\t${substringName} contents:`); + core.info(`'${substring}'`); core.endGroup(); } }