Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backend test framework template #475

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
edb5139
PLA-256 Update tsconfig options
mishayouknowme Dec 13, 2023
e1b19ba
PLA-256 Add assets dir and sampleCode func
mishayouknowme Dec 13, 2023
4d18803
PLA-256 Add script to template
mishayouknowme Dec 13, 2023
a700f5e
PLA-256 Add postSynthesize
mishayouknowme Dec 13, 2023
1e564fc
PLA-256 Update tsconfig
mishayouknowme Dec 13, 2023
c6ccdf3
PLA-256 Update interface
mishayouknowme Dec 13, 2023
dd117c4
PLA-256 Add tasks for remove
mishayouknowme Dec 13, 2023
31ea970
PLA-256 Add tests and eslint-qa
mishayouknowme Dec 13, 2023
ac41389
PLA-256 Add Graphql as option
mishayouknowme Dec 13, 2023
60e2209
PLA-256 Fix tsconfig and codegen files
mishayouknowme Dec 13, 2023
95ed8d6
PLA-256 Add dynamdb set up
mishayouknowme Dec 14, 2023
156da91
PLA-256 Update gql script
mishayouknowme Dec 14, 2023
31deb56
PLA-256 Pass codegen.ts as asset insted sample
mishayouknowme Dec 14, 2023
84654cb
PLA-256 Pass eslint as asset instead sample
mishayouknowme Dec 14, 2023
23815bc
PLA-256 Add axios
mishayouknowme Dec 14, 2023
43ba515
PLA-256 Add test samples
mishayouknowme Dec 14, 2023
e01b8f6
PLA-256 Fix format
mishayouknowme Dec 14, 2023
9d2108f
PLA-256 Remove defaut jest from template
mishayouknowme Dec 15, 2023
6eba19d
PLA-256 Add jest config
mishayouknowme Dec 15, 2023
67896d9
PLA-256 Add format and lint scripts
mishayouknowme Dec 15, 2023
03fd7a4
PLA-256 Add format and lint as task to projen
mishayouknowme Dec 15, 2023
827d11b
PLA-256 Add typecheck script
mishayouknowme Dec 15, 2023
2fc7321
PLA-256 Add properties to tsconfig
mishayouknowme Dec 18, 2023
b845bfe
PLA-256 Mov deps to array
mishayouknowme Dec 18, 2023
651d383
PLA-256 Add prettier ignore
mishayouknowme Dec 18, 2023
c9b4a2c
PLA-256 Pass json files as ts using JsonFile class
mishayouknowme Dec 18, 2023
e4f1043
PLA-256 Add cath error to codegen file
mishayouknowme Dec 18, 2023
ff4ebcf
PLA-256 Fix typo
mishayouknowme Dec 21, 2023
bebe7be
PLA-256 Remove unnecessary devDeps
mishayouknowme Dec 21, 2023
72b22e8
PLA-256 Use addLinters func
mishayouknowme Dec 21, 2023
da96598
PLA-256 Add unit test for gql
mishayouknowme Dec 21, 2023
5c5f069
PLA-256 Add AwsDynamoDb unit tests
mishayouknowme Dec 21, 2023
3559725
PLA-256 Fix format issues in the sample files
mishayouknowme Dec 22, 2023
a99e70e
PLA-256 Remove apollo and fix types issue
mishayouknowme Dec 22, 2023
797a99f
PLA-256 fix unit test
mishayouknowme Dec 22, 2023
9c5754a
PLA-256 Update eslintPath
mishayouknowme Jan 2, 2024
4264a41
PLA-256 Remove tasks
mishayouknowme Jan 17, 2024
a709fc3
PLA-256 Merge branch 'main' into michaelpopov1/pla-256-add-backend-te…
mishayouknowme Jan 17, 2024
7c530ef
PLA-256 Fix format issues
mishayouknowme Jan 17, 2024
ca4de53
PLA-256 Remove projenrc
mishayouknowme Jan 17, 2024
abb1f8c
PLA-256 Remove empty line
mishayouknowme Jan 29, 2024
837a42b
PLA-256 Add eslinignore file
mishayouknowme Jan 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,140 changes: 1,140 additions & 0 deletions src/backend-test/__tests__/__snapshots__/index.ts.snap

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions src/backend-test/__tests__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {synthSnapshot} from 'projen/lib/util/synth'
import {OttofellerBackendTestProject, OttofellerBackendTestProjectOptions} from '..'

describe('Backend-test template', () => {
test('sets defaults', () => {
const project = new TestBackendTestProject({hasGitHooks: true})
const snapshot = synthSnapshot(project)
expect(snapshot).toMatchSnapshot()
})

describe('has GraphQL', () => {
test('enabled by default', () => {
const project = new TestBackendTestProject()
const snapshot = synthSnapshot(project)
expect(snapshot['package.json'].dependencies).toHaveProperty('graphql')
expect(snapshot['package.json'].scripts).toHaveProperty('gql-to-ts')
expect(snapshot['codegen.ts']).toBeDefined()
})

test('disabled with an option', () => {
const project = new TestBackendTestProject({isGraphqlEnabled: false})
const snapshot = synthSnapshot(project)
expect(snapshot['package.json'].dependencies).not.toHaveProperty('graphql')
expect(snapshot['package.json'].scripts).not.toHaveProperty('gql-to-ts')
expect(snapshot['codegen.ts']).not.toBeDefined()
})
})

describe('has AwsDynamoDb', () => {
test('enabled by default', () => {
const project = new TestBackendTestProject()
const snapshot = synthSnapshot(project)
expect(snapshot['package.json'].devDependencies).toHaveProperty('@aws-sdk/client-dynamodb')
expect(snapshot['package.json'].devDependencies).toHaveProperty('@aws-sdk/lib-dynamodb')
})

test('disabled with an option', () => {
const project = new TestBackendTestProject({isAWSDynamoDBEnabled: false})
const snapshot = synthSnapshot(project)
expect(snapshot['package.json'].devDependencies).not.toHaveProperty('@aws-sdk/client-dynamodb')
expect(snapshot['package.json'].devDependencies).not.toHaveProperty('@aws-sdk/lib-dynamodb')
})
})
})
quesabe marked this conversation as resolved.
Show resolved Hide resolved

class TestBackendTestProject extends OttofellerBackendTestProject {
constructor(options: Partial<OttofellerBackendTestProjectOptions> = {}) {
super({
...options,
name: 'test-backend-test-project',
defaultReleaseBranch: 'main',
})
}
}
6 changes: 6 additions & 0 deletions src/backend-test/assets/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
HASURA_GRAPHQL_URL=http://localhost:8080/v1/graphql
HASURA_GRAPHQL_ADMIN_SECRET=111
UPLOAD_AVATAR_URL=https://api.worldcoin-distributors.com/user/upload-avatar
BASE_URL=https://paysis.cyclic.app/
USERNAME=adminius
PASSWORD=supers3cret
5 changes: 5 additions & 0 deletions src/backend-test/assets/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
test-results/**/*
generated/index.ts
schema.graphql
*.generated.ts
*.generated.tsx
5 changes: 5 additions & 0 deletions src/backend-test/assets/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
generated/index.ts
*.generated.ts
tsconfig.json
.eslintrc.json
tsconfig.dev.json
2 changes: 2 additions & 0 deletions src/backend-test/assets/api/auth/index.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './request'
export * from './response'
4 changes: 4 additions & 0 deletions src/backend-test/assets/api/auth/request.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type AuthRequestBody = {
login: string | undefined
password: string | undefined
}
4 changes: 4 additions & 0 deletions src/backend-test/assets/api/auth/response.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type AuthResponseBody = {
token?: string
message?: string
}
114 changes: 114 additions & 0 deletions src/backend-test/assets/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {CodegenConfig} from '@graphql-codegen/cli'
import * as dotenv from 'dotenv'

dotenv.config({path: '.env.local'})
dotenv.config({path: '.env.development'})

if (!process.env.HASURA_GRAPHQL_URL || !process.env.HASURA_GRAPHQL_ADMIN_SECRET) {
throw new Error('HASURA_GRAPHQL_URL or HASURA_GRAPHQL_ADMIN_SECRET does not exist. Check your .env files')
}

const config: CodegenConfig = {
overwrite: true,

config: {
defaultScalarType: 'unknown',
scalars: {
uuid: 'string',
_uuid: 'Array<string>',
timestamp: 'string',
timestamptz: 'string',
numeric: 'string',
jsonb: 'any',
json: 'any',
bigint: 'string',
AWSDate: 'string',
AWSTime: 'string',
AWSDateTime: 'string',
AWSTimestamp: 'string',
AWSEmail: 'string',
AWSJSON: 'string',
AWSURL: 'string',
AWSPhone: 'string',
AWSIPAddress: 'string',
interval: 'string',
date: 'string',
float8: 'string',
},
},

generates: {
// Generate common types
'generated/index.ts': {
schema: [
{
[process.env.HASURA_GRAPHQL_URL]: {
headers: {
'x-hasura-admin-secret': process.env.HASURA_GRAPHQL_ADMIN_SECRET,
'x-hasura-user-id': 'service',
'x-hasura-user-role': 'service',
},
},
},
],
plugins: [
'typescript',
{
add: {
placement: 'prepend',
content: '/* eslint-disable -- Generated */ // @ts-nocheck',

Check warning on line 59 in src/backend-test/assets/codegen.ts

View workflow job for this annotation

GitHub Actions / lint

Unknown word: "nocheck"
},
},
],
config: {
strictScalars: true,
skipDocumentsValidation: {
OverlappingFieldsCanBeMergedRule: true,
},
},
},

// Generate types for graphql requests
src: {
schema: [
{
[process.env.HASURA_GRAPHQL_URL]: {
headers: {
'x-hasura-admin-secret': process.env.HASURA_GRAPHQL_ADMIN_SECRET,
'x-hasura-user-id': 'service',
'x-hasura-user-role': 'service',
},
},
},
],
documents: ['common/graphql/**/*.ts', '!common/graphql/**/*.generated.ts'],
preset: 'near-operation-file',
presetConfig: {
extension: '.generated.ts',
baseTypesPath: '~generated',
},
plugins: ['typescript-operations', 'typescript-graphql-request'],
config: {
skipTypename: true,
useTypeImports: true,
directiveArgumentAndInputFieldMappings: 'Model',
},
},

// Generate schema file for e2e
'schema.graphql': {
schema: [
{
[process.env.HASURA_GRAPHQL_URL]: {
headers: {
'x-hasura-admin-secret': process.env.HASURA_GRAPHQL_ADMIN_SECRET,
},
},
},
],
plugins: ['schema-ast'],
},
},
}

export default config
7 changes: 7 additions & 0 deletions src/backend-test/assets/common/client.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import axios from 'axios'

export const client = axios.create({
baseURL: process.env.BASE_URL,
timeout: 15000,
validateStatus: () => true,
})
1 change: 1 addition & 0 deletions src/backend-test/assets/common/index.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './client'
113 changes: 113 additions & 0 deletions src/backend-test/assets/eslint-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {Linter} from 'eslint'

export const eslintConfig: Linter.Config = {
root: true,
env: {
jest: true,
node: true,
},
ignorePatterns: ['generated/index.ts', '**/*.generated.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'padding-line-between-statements': [
'error',
{
blankLine: 'any',
prev: '*',
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: 'multiline-block-like',
},
{
blankLine: 'always',
prev: 'multiline-block-like',
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: 'multiline-const',
},
{
blankLine: 'always',
prev: 'multiline-const',
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: 'multiline-expression',
},
{
blankLine: 'always',
prev: 'multiline-expression',
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: 'multiline-let',
},
{
blankLine: 'always',
prev: 'multiline-let',
next: '*',
},
{
blankLine: 'never',
prev: ['singleline-const', 'singleline-let'],
next: ['singleline-const', 'singleline-let'],
},
],
'@typescript-eslint/ban-ts-comment': ['off'],
'@typescript-eslint/consistent-type-assertions': ['off'],
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
'@typescript-eslint/no-shadow': ['error'],
'@typescript-eslint/no-unused-expressions': ['error'],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
},
],
curly: ['error'],
'import/no-relative-parent-imports': ['error'],
'no-negated-condition': ['error'],
'no-nested-ternary': ['error'],
'eslint-comments/disable-enable-pair': [
'error',
{
allowWholeFile: true,
},
],
'eslint-comments/no-aggregating-enable': ['error'],
'eslint-comments/no-duplicate-disable': ['error'],
'eslint-comments/no-unlimited-disable': ['error'],
'eslint-comments/no-unused-disable': ['error'],
'eslint-comments/no-unused-enable': ['error'],
'eslint-comments/no-use': [
'error',
{
allow: ['eslint-disable', 'eslint-disable-next-line', 'eslint-enable'],
},
],
'eslint-comments/require-description': [
'error',
{
ignore: ['eslint-enable'],
},
],
},
extends: ['plugin:import/typescript', 'plugin:prettier/recommended'],
plugins: ['@typescript-eslint', 'eslint-comments', 'import', '@ottofeller/ottofeller'],
}
14 changes: 14 additions & 0 deletions src/backend-test/assets/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as dotenv from 'dotenv'
import type {Config} from 'jest'

dotenv.config({path: './.env.local'})
dotenv.config({path: './.env.development'})

const config: Config = {
testTimeout: 60000,
preset: 'ts-jest',
moduleDirectories: ['node_modules', '<rootDir>'],
setupFilesAfterEnv: ['jest-extended/all'],
}

export default config
43 changes: 43 additions & 0 deletions src/backend-test/assets/tests/auth.spec.ts.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {AuthRequestBody, AuthResponseBody} from 'api/auth'
import {AxiosRequestConfig, AxiosResponse} from 'axios'
import {client} from 'common/client'

describe('Authorization & Authentication', () => {
test('Sign in with existing credentials', async () => {
const payload: AxiosRequestConfig<AuthRequestBody> = {
method: 'post',
url: '/auth',
data: {
login: process.env.USERNAME,
password: process.env.PASSWORD,
},
}

const response: AxiosResponse<AuthResponseBody> = await client.request(payload)

expect(response.status).toEqual(200)

expect(response.data).toEqual({
token: expect.any(String),
})
})

test('Sign in with not existing credentials', async () => {
const payload: AxiosRequestConfig<AuthRequestBody> = {
method: 'post',
url: '/auth',
data: {
login: 'invalid',
password: 'invalid',
},
}

const response: AxiosResponse<AuthResponseBody> = await client.request(payload)

expect(response.status).toEqual(404)

expect(response.data).toEqual({
message: expect.any(String),
})
})
})
Loading
Loading