Skip to content

Commit

Permalink
feat: Integration tests (#182)
Browse files Browse the repository at this point in the history
* feat: Integration tests

* fix: Update env vars in the gh workflow

* Update test/integration/picks-controller.spec.ts

Co-authored-by: Lautaro Petaccio <1120791+LautaroPetaccio@users.noreply.github.com>
Signed-off-by: Kevin Szuchet <31735779+kevinszuchet@users.noreply.github.com>

* Update test/integration/picks-controller.spec.ts

Co-authored-by: Lautaro Petaccio <1120791+LautaroPetaccio@users.noreply.github.com>
Signed-off-by: Kevin Szuchet <31735779+kevinszuchet@users.noreply.github.com>

* chore: Remove log

* refactor: Split config files and commands for unit and integrations testing

* fix: Move the init schema script to the root

* fix: Invalid volume without the ./ prefix

* fix: Use pwd instead of relative path

* fix: Use github workspace for the absolute path

* fix: Try with a SQL file instead of sh init schema

* fix: Try without the init script

* chore: Trying with a select 1

* chore: Try changing the entrypoint

* fix: Remove postgress in the end of the entrypoint

* fix: Add quotes to the entrypoint command

* fix: Assign permissions to the whole dir

* fix: Try with the chown

* chore: Echoing something in the entrypoint

* chore: Trying with usr local bin

* chore: Still trying

* chore: Still trying

* chore: Still trying

* chore: Still trying

* chore: Still trying

* chore: Still trying

* chore: Still trying

* chore: Move script to test/db and mount the dir as volume

* fix: Change owner to the workspace before checkout

* feat: Add integration test step to the workflow

* fix: Use correct config files paths

* fix: Specify ports mapping

* chore: Add logs in the init script for more verbosity

* chore: Remove echos

* chore: Try using a SQL script instead

* fix: Remove postgres data volume from workflow

* fix: Remove specific chown

* fix: Try to manually start postgres with compose

* chore: Always run stop containers

* feat: Add run in band option to run integration tests sequentially

* styles: Init schema EOF

---------

Signed-off-by: Kevin Szuchet <31735779+kevinszuchet@users.noreply.github.com>
Co-authored-by: Lautaro Petaccio <1120791+LautaroPetaccio@users.noreply.github.com>
  • Loading branch information
kevinszuchet and LautaroPetaccio committed Jul 3, 2023
1 parent 0777551 commit 773b97a
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 23 deletions.
10 changes: 7 additions & 3 deletions .env.spec
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
HTTP_SERVER_HOST=localhost

PG_COMPONENT_PSQL_DATABASE=marketplace
PG_COMPONENT_PSQL_CONNECTION_STRING=postgres://testuser:testpassword@localhost:5432/marketplace
PG_COMPONENT_PSQL_SCHEMA=favorites
PG_COMPONENT_PSQL_PORT=5432
PG_COMPONENT_PSQL_HOST=localhost

COLLECTIONS_SUBGRAPH_URL=https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mumbai

SNAPSHOT_URL=https://score.snapshot.org/
SNAPSHOT_NETWORK=5
SNAPSHOT_SPACE=1emu.eth
8 changes: 8 additions & 0 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ on: push
jobs:
install:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@master
- name: Start postgres
run: docker compose up -d --renew-anon-volumes
- name: Use Node.js 16.x
uses: actions/setup-node@v3
with:
Expand All @@ -21,7 +24,12 @@ jobs:
if: ${{ always() }}
- name: test
run: npm run test
- name: integration test
run: npm run test:integration
- name: Report coverage
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Stop postgres
if: always()
run: docker compose down -v
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Utilitarian compose file to locally run postgres service
# for integration testing purposes.

version: '3.8'

services:
postgres:
image: postgres
restart: always
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=password
- POSTGRES_DB=marketplace
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/data
- ./test/db/init-schema.sh:/docker-entrypoint-initdb.d/init-schema.sh

volumes:
postgres_data:
12 changes: 0 additions & 12 deletions jest.config.js

This file was deleted.

12 changes: 12 additions & 0 deletions jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"moduleFileExtensions": ["ts", "js"],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"coverageDirectory": "coverage",
"collectCoverageFrom": ["src/**/*.ts", "src/**/*.js"],
"coveragePathIgnorePatterns": ["/node_modules/", "index.ts", "src/migrations"],
"testMatch": ["**/test/unit/*.spec.(ts)"],
"testEnvironment": "node",
"resetMocks": true
}
10 changes: 10 additions & 0 deletions jest.integration.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"moduleFileExtensions": ["ts", "js"],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testMatch": ["**/test/integration/*.spec.(ts)"],
"testEnvironment": "node",
"resetMocks": true,
"setupFilesAfterEnv": ["./jest.setup.ts"]
}
6 changes: 6 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import nock from 'nock'

nock.disableNetConnect()

// Allow localhost connections so we can test local routes and mock servers.
nock.enableNetConnect('127.0.0.1|localhost')
43 changes: 43 additions & 0 deletions package-lock.json

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

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
"start:dev": "ts-node src/index.ts",
"start:watch": "nodemon src/index.ts",
"migrate": "node-pg-migrate --database-url-var PG_COMPONENT_PSQL_CONNECTION_STRING --envPath .env -j ts --tsconfig tsconfig.json -m ./src/migrations",
"test": "jest --forceExit --detectOpenHandles --coverage --verbose",
"test:watch": "jest --watch --verbose",
"test": "jest --forceExit --detectOpenHandles --coverage --verbose -c jest.config.json",
"test:watch": "jest --watch --verbose -c jest.config.json",
"test:integration": "jest --forceExit --detectOpenHandles --verbose -c jest.integration.config.json --runInBand",
"test:integration:watch": "jest --watch --verbose -c jest.integration.config.json --runInBand",
"lint": "eslint -c .eslintrc.json {src/**/*.ts,test/**/*.ts}",
"check:code": "eslint -c .eslintrc.json {src,test}",
"check:prettier": "prettier -c '{src,test}/**/*.{js,ts,json,yml,md}'",
Expand All @@ -24,6 +26,7 @@
"@well-known-components/test-helpers": "^1.5.2",
"husky": "^8.0.3",
"jest": "^29.5.0",
"nock": "^13.3.1",
"nodemon": "^2.0.22",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
Expand Down
27 changes: 22 additions & 5 deletions test/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,36 @@ async function initComponents(): Promise<TestComponents> {
HTTP_SERVER_PORT: (currentPort + 1).toString()
}

const config = await createDotEnvConfigComponent({ path: path.resolve(__dirname, '../.env.default') }, defaultConfig)
const config = await createDotEnvConfigComponent(
{ path: [path.resolve(__dirname, '../.env.default'), path.resolve(__dirname, '../.env.spec')] },
defaultConfig
)
const metrics = await createMetricsComponent(metricDeclarations, { config })
const tracer = createTracerComponent()
const logs = await createLogComponent({ metrics, tracer })

const pg = await createPgComponent({ logs, config, metrics })
// Mock the start function to avoid connecting to a local database
jest.spyOn(pg, 'start').mockResolvedValue()
const databaseUrl = (await config.getString('PG_COMPONENT_PSQL_CONNECTION_STRING')) || ''
const schema = await config.requireString('PG_COMPONENT_PSQL_SCHEMA')

const pg = await createPgComponent(
{ logs, config, metrics },
{
migration: {
databaseUrl,
schema,
dir: path.resolve(__dirname, '../src/migrations'),
migrationsTable: 'pgmigrations',
ignorePattern: '.*\\.map',
direction: 'up'
}
}
)

const server = await createServerComponent<GlobalContext>({ config, logs }, {})
const fetch = await createFetchComponent({ tracer })
instrumentHttpServerWithRequestLogger({ server, logger: logs }, { verbosity: Verbosity.INFO })
const collectionsSubgraph = await createSubgraphComponent({ logs, config, fetch, metrics }, 'subgraph-url')
const COLLECTIONS_SUBGRAPH_URL = await config.requireString('COLLECTIONS_SUBGRAPH_URL')
const collectionsSubgraph = await createSubgraphComponent({ logs, config, fetch, metrics }, COLLECTIONS_SUBGRAPH_URL)
const snapshot = await createSnapshotComponent({ fetch, config })
const schemaValidator = await createSchemaValidatorComponent()
const items = createItemsComponent({ collectionsSubgraph, logs })
Expand Down
12 changes: 12 additions & 0 deletions test/db/init-schema.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE SCHEMA favorites;
-- CREATE THE ROLE AND ASSIGN IT TO THE PREVIOUSLY CREATED DB
CREATE ROLE testuser WITH LOGIN PASSWORD 'testpassword';
GRANT ALL PRIVILEGES ON SCHEMA favorites TO testuser;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp" SCHEMA favorites;
EOSQL
75 changes: 75 additions & 0 deletions test/integration/picks-controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import nock from 'nock'
import { TPick } from '../../src/adapters/picks'
import { DEFAULT_LIST_ID } from '../../src/migrations/1678303321034_default-list'
import { HTTPResponse } from '../../src/types'
import { test } from '../components'

test('picks controller', function ({ components }) {
beforeAll(async () => {
const { config } = components

const collectionsSubgraphUrl = await config.requireString('COLLECTIONS_SUBGRAPH_URL')
const snapshotUrl = await config.requireString('SNAPSHOT_URL')

nock(collectionsSubgraphUrl)
.post(/.*/)
.reply(200, { ok: true, data: { items: [{}] } })

nock(snapshotUrl)
.post(/.*/)
.reply(200, { result: { vp: 1 } })
})

beforeEach(async () => {
await components.pg.query('TRUNCATE TABLE favorites.picks')
})

describe('when making a request to GET /v1/picks/:itemId', () => {
let itemId: string
let userAddress: string
let expectedResponse: HTTPResponse<Pick<TPick, 'userAddress'>>['body']

beforeEach(() => {
itemId = '0x08de0de733cc11081d43569b809c00e6ddf314fb-0'
userAddress = '0x1dec5f50cb1467f505bb3ddfd408805114406b10'
})

describe('and there are no picks in the db', () => {
beforeEach(() => {
expectedResponse = {
ok: true,
data: { limit: 100, page: 0, pages: 0, results: [], total: 0 }
}
})

it('responds with an empty array of picks for the given item id', async () => {
const { localFetch } = components
const response = await localFetch.fetch(`/v1/picks/${itemId}`)

expect(response.status).toEqual(200)
expect(await response.json()).toEqual(expectedResponse)
})
})

describe('and there are some picks in the db', () => {
beforeEach(async () => {
const { lists } = components

await lists.addPickToList(DEFAULT_LIST_ID, itemId, userAddress)

expectedResponse = {
ok: true,
data: { limit: 100, page: 0, pages: 1, results: [{ userAddress }], total: 1 }
}
})

it('responds with the an array with the recently created pick for the given item id', async () => {
const { localFetch } = components
const response = await localFetch.fetch(`/v1/picks/${itemId}`)

expect(response.status).toEqual(200)
expect(await response.json()).toEqual(expectedResponse)
})
})
})
})
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
},
"include": ["src", "test"]
"include": ["src", "test", "jest.setup.ts"]
}

0 comments on commit 773b97a

Please sign in to comment.