Skip to content

Commit

Permalink
Unittests (#5)
Browse files Browse the repository at this point in the history
* Added test dependencies

* Added unittests for validating generated schemas

* Added Prettier config file

* Updated readme

* Added workflows for build and test actions

* Update test gh action name

* upport for typescript on tests

* Refactored schema tests
  • Loading branch information
alfetopito authored Jul 22, 2022
1 parent aff22eb commit 2703419
Show file tree
Hide file tree
Showing 8 changed files with 2,082 additions and 26 deletions.
51 changes: 51 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build

# Run on pushes to main or PRs
on:
# Pull request hook without any config. Launches for every pull request
pull_request:
# Launches for pushes to main or dev
push:
branches:
- main
# Launches build when release is published
release:
types: [ published ]

jobs:
build:
name: Build Package
runs-on: ubuntu-latest

steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Remove broken apt repos [Ubuntu]
if: ${{ matrix.os }} == 'ubuntu-latest'
run: |
for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3

- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- run: |
# Due to some dependencies yarn may randomly throw an error about invalid cache
# This approach is taken from https://github.com/yarnpkg/yarn/issues/7212#issuecomment-506155894 to fix the issue
# Another approach is to install with flag --network-concurrency 1, but this will make the installation pretty slow (default value is 8)
mkdir .yarncache
yarn install --cache-folder ./.yarncache --frozen-lockfile
rm -rf .yarncache
yarn cache clean
- name: Build app
run: yarn build
1 change: 0 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14.x
registry-url: 'https://registry.npmjs.org'
scope: '@cowprotocol'
- run: yarn --frozen-lockfile
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Unit tests
on: [ push, pull_request ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Checkout
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3

- name: Yarn cache
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Yarn install
run: |
mkdir .yarncache
yarn install --cache-folder ./.yarncache --frozen-lockfile
rm -rf .yarncache
yarn cache clean
- name: Run tests
run: yarn test
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 120
}
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const schema = require('@cowprotocol/app-data/schemas/v0.4.0.json')
There are also type definitions

```js
import {v0_4_0} from '@cowprotocol/app-data'
import { v0_4_0 } from '@cowprotocol/app-data'

// Note: this example is
function createAppDataV0_4_0(
Expand Down Expand Up @@ -60,13 +60,12 @@ import {
createAppDataDoc, createReferrerMetadata, createQuoteMetadata
} from '@cowprotocol/app-data'

const referrer = createReferrerMetadata({address: '0x...'})
const quote = createQuoteMetadata({slippageBips: '100'})
const appDataDoc = createAppDataDoc({appCode: 'myApp', metadata: {referrer, quote}})
const referrer = createReferrerMetadata({ address: '0x...' })
const quote = createQuoteMetadata({ slippageBips: '100' })
const appDataDoc = createAppDataDoc({ appCode: 'myApp', metadata: { referrer, quote } })
```

## TODO:

- [ ] Add tests for:
- [ ] Consuming only the schema
- [ ] Importing the type definitions
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"clean": "rm -rf dist/* && rm -rf src/generatedTypes/* && rm -rf schemas/",
"compile": "ts-node --esm src/scripts/compile.ts --experimental-specifier-resolution=node",
"build": "yarn clean && yarn compile && microbundle",
"test": "jest",
"prepare": "npm run build"
},
"repository": {
Expand All @@ -32,12 +33,33 @@
},
"homepage": "https://github.com/cowprotocol/app-data#readme",
"devDependencies": {
"@babel/core": "^7.18.9",
"@babel/preset-env": "^7.18.9",
"@babel/preset-typescript": "^7.18.6",
"@types/jest": "^28.1.6",
"@types/semver-sort": "^0.0.1",
"ajv": "^8.11.0",
"babel-jest": "^28.1.3",
"jest": "^28.1.3",
"json-schema-ref-parser": "^9.0.9",
"json-schema-to-typescript": "^10.1.5",
"microbundle": "^0.15.0",
"prettier": "^2.7.1",
"semver-sort": "^1.0.0",
"ts-node": "^10.8.2",
"typescript": "^4.7.4"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"@babel/preset-typescript"
]
}
}
217 changes: 217 additions & 0 deletions test/schema.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import Ajv, { ValidateFunction } from 'ajv'

import schemaV0_1_0 from '../schemas/v0.1.0.json'
import schemaV0_2_0 from '../schemas/v0.2.0.json'
import schemaV0_3_0 from '../schemas/v0.3.0.json'
import schemaV0_4_0 from '../schemas/v0.4.0.json'

const ADDRESS = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9'
const REFERRER_V0_1_0 = { address: ADDRESS, version: '0.1.0' }
const QUOTE_V0_1_0 = { sellAmount: '123123', buyAmount: '1314123', version: '0.1.0' }
const QUOTE_V0_2_0 = { slippageBips: '1', version: '0.2.0' }

const MISSING_VERSION_ERROR = [
{
instancePath: '',
keyword: 'required',
message: "must have required property 'version'",
params: { missingProperty: 'version' },
schemaPath: '#/required',
},
]

describe('Schema v0.1.0', () => {
const ajv = new Ajv()
const validator = ajv.compile(schemaV0_1_0)

const BASE_DOCUMENT = {
version: '0.1.0',
metadata: {},
}

test('Minimal valid schema', _buildAssertValidFn(validator, BASE_DOCUMENT))

test('Missing required fields', _buildAssertInvalidFn(validator, {}, MISSING_VERSION_ERROR))

test(
'With referrer metadata',
_buildAssertValidFn(validator, {
...BASE_DOCUMENT,
appCode: 'MyApp',
metadata: {
referrer: REFERRER_V0_1_0,
},
})
)

test(
'With invalid referrer metadata',
_buildAssertInvalidFn(
validator,
{
...BASE_DOCUMENT,
appCode: 'MyApp',
metadata: {
referrer: { address: '0xas', version: '0.1.0' },
},
},
[
{
instancePath: '/metadata/referrer/address',
keyword: 'pattern',
message: 'must match pattern "^0x[a-fA-F0-9]{40}$"',
params: { pattern: '^0x[a-fA-F0-9]{40}$' },
schemaPath: '#/properties/metadata/properties/referrer/properties/address/pattern',
},
]
)
)
})

describe('Schema v0.2.0', () => {
const ajv = new Ajv()
const validator = ajv.compile(schemaV0_2_0)

const BASE_DOCUMENT = {
version: '0.2.0',
metadata: {},
}

test('Minimal valid schema', _buildAssertValidFn(validator, BASE_DOCUMENT))

test('Missing required fields', _buildAssertInvalidFn(validator, {}, MISSING_VERSION_ERROR))

test(
'With referrer v0.1.0 and quote v0.1.0 metadata',
_buildAssertValidFn(validator, {
...BASE_DOCUMENT,
appCode: 'MyApp',
metadata: {
referrer: REFERRER_V0_1_0,
quote: QUOTE_V0_1_0,
},
})
)

test(
'With invalid quote metadata v0.1.0',
_buildAssertInvalidFn(
validator,
{
...BASE_DOCUMENT,
appCode: 'MyApp',
metadata: {
referrer: REFERRER_V0_1_0,
quote: { sellAmount: 'xx12d', buyAmount: 0.13, version: '0.1.0' },
},
},
[
{
instancePath: '/metadata/quote/sellAmount',
keyword: 'pattern',
message: 'must match pattern "^\\d+$"',
params: { pattern: '^\\d+$' },
schemaPath: '#/properties/metadata/properties/quote/properties/buyAmount/pattern',
},
]
)
)
})

describe('Schema v0.3.0', () => {
const ajv = new Ajv()
const validator = ajv.compile(schemaV0_3_0)

const BASE_DOCUMENT = {
version: '0.3.0',
metadata: {},
}

test('Minimal valid schema', _buildAssertValidFn(validator, BASE_DOCUMENT))

test('Missing required fields', _buildAssertInvalidFn(validator, {}, MISSING_VERSION_ERROR))

test(
'With environment and full metadata (both v0.1.0)',
_buildAssertValidFn(validator, {
...BASE_DOCUMENT,
appCode: 'MyApp',
environment: 'prod',
metadata: {
referrer: REFERRER_V0_1_0,
quote: QUOTE_V0_1_0,
},
})
)
})

describe('Schema v0.4.0', () => {
const ajv = new Ajv()
const validator = ajv.compile(schemaV0_4_0)

const BASE_DOCUMENT = {
version: '0.4.0',
metadata: {},
}

test('Minimal valid schema', _buildAssertValidFn(validator, BASE_DOCUMENT))

test('Missing required fields', _buildAssertInvalidFn(validator, {}, MISSING_VERSION_ERROR))

test(
'With quote metadata v0.2.0',
_buildAssertValidFn(validator, {
...BASE_DOCUMENT,
appCode: 'MyApp',
environment: 'prod',
metadata: {
referrer: REFERRER_V0_1_0,
quote: QUOTE_V0_2_0,
},
})
)

test(
'With invalid quote metadata v0.2.0',
_buildAssertInvalidFn(
validator,
{
...BASE_DOCUMENT,
appCode: 'MyApp',
environment: 'prod',
metadata: {
referrer: REFERRER_V0_1_0,
quote: QUOTE_V0_1_0,
},
},
[
{
instancePath: '/metadata/quote',
keyword: 'required',
message: "must have required property 'slippageBips'",
params: { missingProperty: 'slippageBips' },
schemaPath: '#/properties/metadata/properties/quote/required',
},
]
)
)
})

function _buildAssertValidFn(validator: ValidateFunction, doc: any) {
return () => {
// when
const actual = validator(doc)
// then
expect(actual).toBeTruthy()
}
}

function _buildAssertInvalidFn(validator: ValidateFunction, doc: any, errors: any) {
return () => {
// when
const actual = validator(doc)
// then
expect(actual).toBeFalsy()
expect(validator.errors).toEqual(errors)
}
}
Loading

0 comments on commit 2703419

Please sign in to comment.