Skip to content

Commit

Permalink
fix: Replace implicit workflows source with explicit local source (
Browse files Browse the repository at this point in the history
  • Loading branch information
shrink committed Jun 13, 2021
1 parent 9686bde commit 0d888b7
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 56 deletions.
19 changes: 10 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ jobs:
- name: Test developer is greeted
uses: ./
with:
assertion: workflows://is-equal
assertion: local://.github/workflows/assertions/is-equal
actual: "${{ env.greeting }}"
expected: "Hello, World!"
- name: Test developer is dismissed
uses: ./
continue-on-error: true
with:
assertion: workflows://is-equal
assertion: local://.github/workflows/assertions/is-equal
actual: "${{ env.dismissal }}"
expected: "Goodbye, World!"
- name: Test each line is the greeting
uses: ./
with:
assertion: workflows://is-equal
assertion: local://.github/workflows/assertions/is-equal
actual: |
${{ env.greeting }}
${{ env.greeting }}
Expand All @@ -44,14 +44,14 @@ jobs:
- name: Test an even number is even
uses: ./
with:
assertion: workflows://is-even
assertion: local://.github/workflows/assertions/is-even
actual: 2
type: number
- name: Test an odd number is not even
continue-on-error: true
uses: ./
with:
assertion: workflows://is-even
assertion: local://.github/workflows/assertions/is-even
actual: 3
type: number
npm-assertions:
Expand Down Expand Up @@ -114,7 +114,7 @@ jobs:
id: equal-strings
uses: ./
with:
assertion: workflows://is-equal
assertion: local://.github/workflows/assertions/is-equal
actual: "Hello, World!"
expected: "Hello, World!"
- name: Test `message` output is set from Result `message`
Expand All @@ -130,11 +130,12 @@ jobs:
assertion: npm://@assertions/is-equal
actual: "${{ steps.equal-strings.outputs.pass }}"
expected: "true"
test-dist-v1:
test-dist:
runs-on: ubuntu-latest
steps:
- uses: pr-mpt/actions-assert@v1
- uses: actions/checkout@v2
- uses: pr-mpt/actions-assert@v2
with:
assertion: workflows://is-equal
assertion: local://.github/workflows/assertions/is-equal
actual: "Hello, World!"
expected: "Hello, World!"
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Assert

A GitHub Action for asserting **actual** is **expected** in GitHub Workflows.
Designed for GitHub Action integration tests and build pipelines.
Designed for GitHub Action integration tests and robust build pipelines.

* Cast action input values from strings to `type` for type safety
* Add custom Javascript assertions to your project to meet unique testing requirements
* Distribute reusable assertions via [npm][npm]
* Write local Javascript assertions to meet project-specific testing needs
* Run tests against multiple values using `each`

```yaml
Expand All @@ -13,10 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Test actor is @shrink
uses: pr-mpt/actions-assert@v1
uses: pr-mpt/actions-assert@v2
with:
assertion: npm://@assertions/is-equal
actual: ${{ github.actor }}
actual: "${{ github.actor }}"
expected: shrink
```
Expand All @@ -26,11 +27,12 @@ jobs:
| Name | Description | Default | Examples |
| :--- | :---------- | :------ | :------- |
| **`assertion`** | **Reference to a supported [assertion](#assertions)** | | **`npm://@assertions/is-equal`** |
| **`actual`** | **Dynamic value to perform test on** | | **`${{steps.m.outputs.greeting}}`** |
| `expected` | Value that `actual` should match | | `Hello, World!` |
| **`assertion`** | **Reference to a supported [assertion](#assertions)** in `source://name` format | | **`npm://@assertions/is-equal`**<br/>**`local://is-even`** |
| `expected` | Value the assertion is looking for | | `Hello, World!` |
| `actual` | Value the assertion will test against the expected value | | `${{steps.fields.outputs.greeting}}` |
| `type` | A supported [data type](#data-types) that `actual` and `expected` will be cast to before performing assertion | `string` | `string` `json` `number` |
| `each` | Parse multi-line `actual` into many values and test each | `false` | `true` `false` |
| `local-path` | Path to directory containing `local` assertion | `${{github.workspace}}` | `.github/workflows/assertions` |

### Assertions

Expand All @@ -47,13 +49,13 @@ module.exports = function (expected, actual) {
}
```

Assertions are resolved using `type` and `name` accepted in `type://name`
Assertions are resolved using `source` and `name` accepted in `source://name`
format.

| Type | Resolved To | Example |
| Source | Resolved To | Example |
| :--- | :---------- | :------ |
| `workflows` | A Javascript file in `.github/workflows/assertions` that exports an assertion as default | `workflows://is-equal` |
| `npm` | An [npm][npm] package with an assertion as the [main exported module][package.json/main] | `npm://@assertions/is-equal` |
| `local` | A Javascript file (on the runner's filesystem) that exports an assertion as default | `local://is-equal` |

#### `npm`

Expand Down Expand Up @@ -102,7 +104,7 @@ jobs:
major: true
minor: false
- name: Assert alias is prefixed
uses: pr-mpt/actions-assert@v1
uses: pr-mpt/actions-assert@v2
with:
assertion: npm://@assertions/starts-with
each: true
Expand All @@ -120,3 +122,4 @@ jobs:
[@assertions/is-strictly-equal]: https://npmjs.com/package/@assertions/is-strictly-equal
[@assertions/starts-with]: https://npmjs.com/package/@assertions/starts-with
[npm/@assertions]: https://www.npmjs.com/org/assertions
[workflows/workspace]: https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context
21 changes: 12 additions & 9 deletions __tests__/assertions.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import {resolveAssertion} from '../src/assertions'

const isEven = require(`../.github/workflows/assertions/is-even.js`)

describe('assertions resolver', () => {
describe('workflows resolution', () => {
it('resolves to workflows assertions directory', () => {
describe('local resolution', () => {
it('resolves to specified assertions directory', () => {
expect.assertions(1)

const isEven = require('../.github/workflows/assertions/is-even')

resolveAssertion('workflows://is-even').then(assertion =>
resolveAssertion(
'local://is-even',
'../.github/workflows/assertions'
).then(assertion =>
expect(assertion.toString()).toStrictEqual(isEven.toString())
)
})
Expand All @@ -27,16 +30,16 @@ describe('assertions resolver', () => {
})
})

it('throws error when no type is provided', () => {
it('throws error when no source is provided', () => {
expect.assertions(1)
return resolveAssertion('without-type').catch(e =>
return resolveAssertion('without-source').catch(e =>
expect(e instanceof URIError).toBe(true)
)
})

it('throws error when type does not have resolver', () => {
it('throws error when source does not have resolver', () => {
expect.assertions(1)
return resolveAssertion('invalid-type://example').catch(e =>
return resolveAssertion('invalid-source://example').catch(e =>
expect(e instanceof RangeError).toBe(true)
)
})
Expand Down
12 changes: 8 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ inputs:
assertion:
description: "Name of the assertion to run against value"
required: true
expected:
description: "Value the assertion is looking for"
required: false
actual:
description: "Dynamic value to test against"
required: true
expected:
description: "Value that `actual` should match"
required: false
type:
description: "Javascript data type that actual and expected will be cast to"
default: "string"
required: true
each:
description: "Parse multi-line `actual` into many values and assert against each"
required: false
default: "false"
required: false
local-path:
description: "Path to assertions on the runner's filesystem"
default: "${{ github.workspace }}"
required: true
outputs:
message:
description: "Human readable result of the assertion"
Expand Down
18 changes: 8 additions & 10 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

21 changes: 10 additions & 11 deletions src/assertions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import {Assertion} from './execute'
import {PluginManager} from 'live-plugin-manager'

async function loadAssertionFromFile(filename: string): Promise<Assertion> {
return eval(`require('${filename}')`)
}

async function loadAssertionFromNpmPackage(name: string): Promise<Assertion> {
const manager = new PluginManager()

Expand All @@ -15,22 +11,25 @@ async function loadAssertionFromNpmPackage(name: string): Promise<Assertion> {

const resolvers = {
npm: loadAssertionFromNpmPackage,
workflows: async (name: string): Promise<Assertion> =>
loadAssertionFromFile(`./../.github/workflows/assertions/${name}.js`)
local: async (name: string, path: string): Promise<Assertion> =>
eval(`require('${path}/${name}.js')`)
}

export async function resolveAssertion(resource: string): Promise<Assertion> {
export async function resolveAssertion(
resource: string,
localPath = ''
): Promise<Assertion> {
if (!resource.includes('://')) {
throw new URIError(`Assertion reference is not valid, must include type.`)
}

const [type, name] = resource.split('://')
const [source, name] = resource.split('://')

if (!resolvers.hasOwnProperty(type)) {
throw new RangeError(`Assertion type ${type} is not supported.`)
if (!resolvers.hasOwnProperty(source)) {
throw new RangeError(`Assertion source ${source} is not supported.`)
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return resolvers[type](name)
return resolvers[source](name, localPath)
}
6 changes: 5 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ async function run(): Promise<void> {
const assertion: string = core.getInput('assertion')
const type: string = core.getInput('type')
const each: boolean = core.getBooleanInput('each')
const localPath: string = core.getInput('local-path')

if (type in types === false) {
throw new Error(
Expand All @@ -26,7 +27,10 @@ async function run(): Promise<void> {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const typeOfInput: InputType = types[type]
const assertionFunction: Assertion = await resolveAssertion(assertion)
const assertionFunction: Assertion = await resolveAssertion(
assertion,
localPath
)

const actualValues: String[] = each === true ? actual.split('\n') : [actual]

Expand Down

0 comments on commit 0d888b7

Please sign in to comment.