feat: add few classy tests on auth
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,8 @@ out
|
||||
tmp
|
||||
|
||||
coverage
|
||||
allure-results
|
||||
allure-report
|
||||
.nyc_output
|
||||
*.log
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.js]
|
||||
indent_size = 4
|
||||
|
||||
[*.json]
|
||||
indent_size = 4
|
||||
@@ -1,2 +0,0 @@
|
||||
api
|
||||
node_modules
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-var": ["error"],
|
||||
"curly": ["error", "all"],
|
||||
"keyword-spacing": ["error", { "before": true, "after": true }],
|
||||
"space-before-function-paren": ["error", {
|
||||
"anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}],
|
||||
"quotes": ["error", "single", { "avoidEscape": true }],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"strict": ["error", "global"],
|
||||
"semi": ["error", "never"],
|
||||
"indent": ["error", 4, {"SwitchCase": 1}],
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"@typescript-eslint/interface-name-prefix": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
194
tests/.jest/jest-custom-reporter.ts
Normal file
194
tests/.jest/jest-custom-reporter.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { AllureReporterApi, jasmine_, registerAllureReporter } from 'jest-allure2-adapter'
|
||||
import { ContentType, Severity } from 'allure-js-commons'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type TestDecorator = (
|
||||
target: object,
|
||||
property: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) => PropertyDescriptor
|
||||
export class JasmineAllureReporter implements jasmine_.CustomReporter {
|
||||
allure: AllureReporterApi
|
||||
|
||||
constructor(allure: AllureReporterApi) {
|
||||
this.allure = allure
|
||||
}
|
||||
|
||||
suiteStarted(suite?: jasmine_.CustomReporterResult): void {
|
||||
this.allure.startGroup(suite.description)
|
||||
// some actions here on suite started
|
||||
}
|
||||
|
||||
suiteDone(): void {
|
||||
// some actions here on suite end
|
||||
this.allure.endGroup()
|
||||
}
|
||||
|
||||
specStarted(spec: jasmine_.CustomReporterResult): void {
|
||||
this.allure.startTest(spec)
|
||||
// some actions here on test started
|
||||
}
|
||||
|
||||
specDone(spec: jasmine_.CustomReporterResult): void {
|
||||
// some actions here on spec end
|
||||
this.allure.endTest(spec)
|
||||
}
|
||||
}
|
||||
|
||||
registerAllureReporter(undefined, (allure) => new JasmineAllureReporter(allure))
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
reporter: AllureReporterApi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAllure(): AllureReporterApi {
|
||||
// @ts-ignore - we are checking if reporter is defined
|
||||
if (!global.reporter) {
|
||||
throw new Error('Unable to find Allure implementation')
|
||||
}
|
||||
// @ts-ignore - we know that reporter is an AllureReporterApi
|
||||
return global.reporter
|
||||
}
|
||||
|
||||
export function step<T>(nameFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return (target: object, propertyKey: string, descriptor: PropertyDescriptor) => {
|
||||
const original: object = descriptor.value
|
||||
let callable: (args: T) => void = () => {
|
||||
/* */
|
||||
}
|
||||
|
||||
if (typeof original === 'function') {
|
||||
descriptor.value = function (...args: [T]) {
|
||||
try {
|
||||
const value: string = typeof nameFn === 'function' ? nameFn.apply(this, args) : nameFn
|
||||
callable = () => getAllure().step(value, () => original.apply(this, args))
|
||||
// tslint:disable-next-line:no-console
|
||||
console.info(`Step: ${value || nameFn}`)
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.error(`[ERROR] Failed to apply decorator: ${e}`)
|
||||
}
|
||||
return callable.apply(this, args)
|
||||
}
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
}
|
||||
|
||||
export function attachment<T>(name: string, type: ContentType) {
|
||||
return (
|
||||
_target: object,
|
||||
_propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
): PropertyDescriptor => {
|
||||
const original: object = descriptor.value
|
||||
let callable: (args: T) => void = () => {
|
||||
/* */
|
||||
}
|
||||
|
||||
if (typeof original === 'function') {
|
||||
descriptor.value = async function (...args: [T]) {
|
||||
try {
|
||||
const content: Buffer | string = await original.apply(this, args)
|
||||
callable = () =>
|
||||
getAllure().step(name, () => {
|
||||
getAllure().attachment(type.toString(), content, type)
|
||||
})
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.error(`[ERROR] Failed to apply decorator: ${e}`)
|
||||
}
|
||||
return callable.apply(this, args)
|
||||
}
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
}
|
||||
|
||||
export function attach(name: string, content: string | Buffer, type: ContentType): void {
|
||||
getAllure().step(name, () => {
|
||||
getAllure().attachment(type.toString(), content, type)
|
||||
})
|
||||
}
|
||||
|
||||
export function log(name: string, description?: string): void {
|
||||
console.info(description ? `${name}: ${description}` : name)
|
||||
getAllure().step(name, () => {
|
||||
if (description) {
|
||||
getAllure().step(description, () => {
|
||||
/* */
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function feature<T>(featureFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return processDecorator(featureFn, (name) => getAllure().feature(name))
|
||||
}
|
||||
|
||||
export function story<T>(storyFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return processDecorator(storyFn, (name) => getAllure().story(name))
|
||||
}
|
||||
|
||||
export function severity<T>(
|
||||
severityFn: Severity | string | ((arg: T) => string | Severity)
|
||||
): TestDecorator {
|
||||
return processDecorator(severityFn, (name: Severity) => getAllure().severity(name))
|
||||
}
|
||||
|
||||
export function tag<T>(tagFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return processDecorator(tagFn, (name) => getAllure().tag(name))
|
||||
}
|
||||
|
||||
export function owner<T>(ownerFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return processDecorator(ownerFn, (name) => getAllure().owner(name))
|
||||
}
|
||||
|
||||
export function description<T>(descriptionFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return processDecorator(descriptionFn, (text) => getAllure().description(text))
|
||||
}
|
||||
|
||||
function processDecorator<T>(
|
||||
parameterFn: string | ((arg: T) => string),
|
||||
reporterFn: (arg: string) => void
|
||||
): TestDecorator {
|
||||
return (target: object, property: string, descriptor: PropertyDescriptor) => {
|
||||
return processDescriptor(parameterFn, reporterFn, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
function processDescriptor<T>(
|
||||
parameterFn: string | ((arg: T) => string),
|
||||
reporterFn: (arg: string) => void,
|
||||
descriptor: PropertyDescriptor
|
||||
): PropertyDescriptor {
|
||||
const original: object = descriptor.value
|
||||
if (typeof original === 'function') {
|
||||
descriptor.value = function (...args: [T]) {
|
||||
try {
|
||||
const value: string =
|
||||
typeof parameterFn === 'function' ? parameterFn.apply(this, args) : parameterFn
|
||||
reporterFn(value)
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.error(`[ERROR] Failed to apply decorator: ${e}`)
|
||||
}
|
||||
return original.apply(this, args)
|
||||
}
|
||||
}
|
||||
|
||||
for (const prop of Object.keys(original)) {
|
||||
if (original.hasOwnProperty(prop) && prop.startsWith('__testdeck_')) {
|
||||
// @ts-ignore - we know that prop exists
|
||||
descriptor.value[prop] = original[prop]
|
||||
}
|
||||
}
|
||||
|
||||
return descriptor
|
||||
}
|
||||
8
tests/.jest/jest-env.js
Normal file
8
tests/.jest/jest-env.js
Normal file
@@ -0,0 +1,8 @@
|
||||
process.env.SUPABASE_DB_HOST = 'localhost'
|
||||
process.env.SUPABASE_DB_PORT = '54322'
|
||||
process.env.SUPABASE_GOTRUE = 'http://localhost:54321/auth/v1'
|
||||
process.env.SUPABASE_URL = 'http://localhost:54321'
|
||||
process.env.SUPABASE_KEY_ANON =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs'
|
||||
process.env.SUPABASE_KEY_ADMIN =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU'
|
||||
4
tests/.prettierignore
Normal file
4
tests/.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
api
|
||||
node_modules
|
||||
package-lock.json
|
||||
docker*
|
||||
7
tests/.prettierrc
Normal file
7
tests/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
||||
373
tests/features/javascript/authentication.spec.ts
Normal file
373
tests/features/javascript/authentication.spec.ts
Normal file
@@ -0,0 +1,373 @@
|
||||
import { suite, test } from '@testdeck/jest'
|
||||
import { faker } from '@faker-js/faker'
|
||||
import { Severity } from 'allure-js-commons'
|
||||
import postgres from 'postgres'
|
||||
import crossFetch from 'cross-fetch'
|
||||
|
||||
import {
|
||||
ApiError,
|
||||
createClient,
|
||||
Session,
|
||||
SupabaseClient,
|
||||
SupabaseClientOptions,
|
||||
User,
|
||||
} from '@supabase/supabase-js'
|
||||
|
||||
import { FEATURE } from '../templates/enums'
|
||||
import { description, feature, log, severity, step } from '../../.jest/jest-custom-reporter'
|
||||
|
||||
@suite('authentication')
|
||||
class Authentication {
|
||||
private static sql = postgres({
|
||||
host: process.env.SUPABASE_DB_HOST,
|
||||
port: parseInt(process.env.SUPABASE_DB_PORT),
|
||||
database: 'postgres',
|
||||
username: 'postgres',
|
||||
password: 'postgres',
|
||||
})
|
||||
|
||||
@step('terminate sql connection')
|
||||
static async after(): Promise<any> {
|
||||
try {
|
||||
Authentication.sql.end({ timeout: 100 })
|
||||
return Promise.resolve(null)
|
||||
} catch (err) {
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
|
||||
@feature(FEATURE.AUTHENTICATION)
|
||||
@severity(Severity.BLOCKER)
|
||||
@description('When user sign up then corresponding user in auth schema should be created')
|
||||
@test
|
||||
async 'signup should create user'() {
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
|
||||
const fakeUser = {
|
||||
email: faker.internet.exampleEmail(),
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
}
|
||||
const { user, session, error: signUpError } = await this.signUp(supabase, fakeUser)
|
||||
|
||||
expect(user).toBeDefined()
|
||||
expect(user.email).toEqual(fakeUser.email.toLowerCase())
|
||||
expect(session).toBeDefined()
|
||||
expect(signUpError).toBeNull()
|
||||
|
||||
const [createdUser] = await this.selectUser(user)
|
||||
expect(createdUser.email).toEqual(fakeUser.email.toLowerCase())
|
||||
}
|
||||
|
||||
@feature(FEATURE.AUTHENTICATION)
|
||||
@severity(Severity.BLOCKER)
|
||||
@description('When user sign up then he should not be logged in until he confirms his email')
|
||||
@test
|
||||
async 'new users'() {
|
||||
// sign up user
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
|
||||
const fakeUser = {
|
||||
email: faker.internet.exampleEmail(),
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
}
|
||||
const { user, error: signUpError } = await this.signUp(supabase, fakeUser)
|
||||
|
||||
expect(user).toBeDefined()
|
||||
expect(user.email).toEqual(fakeUser.email.toLowerCase())
|
||||
expect(signUpError).toBeNull()
|
||||
|
||||
// check if user is not signed in cause he has not confirmed his email
|
||||
const { error: errorInsertFailed } = await this.insertProfile(supabase, user, fakeUser)
|
||||
log('check if insert failed caused user has not confirmed email')
|
||||
expect(errorInsertFailed).not.toBeNull()
|
||||
|
||||
// confirm user email and sign in
|
||||
const [{ confirmation_token: token }] = await this.getConfirmationToken(user)
|
||||
const verifyResponse = await this.verify(token)
|
||||
expect(verifyResponse.ok).toBeTruthy()
|
||||
|
||||
const { error: signInError } = await supabase.auth.signIn({
|
||||
email: fakeUser.email,
|
||||
password: fakeUser.password,
|
||||
})
|
||||
expect(signInError).toBeNull()
|
||||
|
||||
// check if user is signed in
|
||||
const { data: profile, error: errorInsert } = await this.insertProfile(supabase, user, fakeUser)
|
||||
expect(errorInsert).toBeNull()
|
||||
expect(profile.username).toMatch(fakeUser.username)
|
||||
|
||||
const { data: profileGot } = await this.getUserProfile(supabase)
|
||||
expect(profileGot.username).toMatch(profile.username)
|
||||
|
||||
// check if user is able to sign out
|
||||
const { error } = await this.signOut(supabase)
|
||||
expect(error).toBeNull()
|
||||
}
|
||||
|
||||
@feature(FEATURE.AUTHENTICATION)
|
||||
@severity(Severity.BLOCKER)
|
||||
@description('When user sign up with phone then he should be logged in')
|
||||
@test
|
||||
async 'new users by phone'() {
|
||||
// sign up user
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
|
||||
const fakeUser = {
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
phone: faker.phone.phoneNumber('!#!##!######'),
|
||||
}
|
||||
const { user, session, error: signUpError } = await this.signUpByPhone(supabase, fakeUser)
|
||||
|
||||
expect(user).toBeDefined()
|
||||
expect(user.phone).toEqual(fakeUser.phone)
|
||||
expect(session).toBeDefined()
|
||||
expect(signUpError).toBeNull()
|
||||
|
||||
// check if user is signed in
|
||||
const { data: profile, error: errorInsert } = await this.insertProfile(supabase, user, fakeUser)
|
||||
expect(errorInsert).toBeNull()
|
||||
expect(profile.username).toMatch(fakeUser.username)
|
||||
|
||||
const { data: profileGot } = await this.getUserProfile(supabase)
|
||||
expect(profileGot.username).toMatch(profile.username)
|
||||
|
||||
// check if user is able to sign out
|
||||
const { error } = await this.signOut(supabase)
|
||||
expect(error).toBeNull()
|
||||
}
|
||||
|
||||
@feature(FEATURE.AUTHENTICATION)
|
||||
@severity(Severity.BLOCKER)
|
||||
@description('When user is already signed up then he should be able to log in')
|
||||
@test
|
||||
async 'existing users'() {
|
||||
// create user
|
||||
const fakeUser = await this.createUser()
|
||||
|
||||
// sign in as user
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
const {
|
||||
session,
|
||||
user,
|
||||
error: signInError,
|
||||
} = await supabase.auth.signIn({
|
||||
email: fakeUser.email,
|
||||
password: fakeUser.password,
|
||||
})
|
||||
|
||||
expect(user).toBeDefined()
|
||||
expect(user.email).toEqual(fakeUser.email.toLowerCase())
|
||||
expect(session).toBeDefined()
|
||||
expect(signInError).toBeNull()
|
||||
|
||||
// check if user is signed in correctly and rls is working
|
||||
const { data: profileInserted, error: errorInsert } = await this.insertProfile(
|
||||
supabase,
|
||||
user,
|
||||
fakeUser
|
||||
)
|
||||
expect(errorInsert).toBeNull()
|
||||
expect(profileInserted.username).toMatch(fakeUser.username)
|
||||
|
||||
const { data: profileGot } = await this.getUserProfile(supabase)
|
||||
expect(profileGot.username).toMatch(profileInserted.username)
|
||||
|
||||
// check if user is able to sign out
|
||||
const { error } = await this.signOut(supabase)
|
||||
expect(error).toBeNull()
|
||||
}
|
||||
|
||||
@feature(FEATURE.AUTHENTICATION)
|
||||
@severity(Severity.NORMAL)
|
||||
@description('When user is signed in then he should be able to get his info and metadata')
|
||||
@test
|
||||
async 'get user'() {
|
||||
// create user
|
||||
const username = faker.internet.userName()
|
||||
const date = faker.date.recent().toUTCString()
|
||||
const fakeUser = await this.createUser({
|
||||
username: username,
|
||||
date: date,
|
||||
})
|
||||
|
||||
// sign in as user
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
await supabase.auth.signIn({
|
||||
email: fakeUser.email,
|
||||
password: fakeUser.password,
|
||||
})
|
||||
|
||||
// get signed in user data
|
||||
const user = this.getUser(supabase)
|
||||
|
||||
log('Check if user is signed in correctly and can get his data')
|
||||
expect(user).toBeDefined()
|
||||
expect(user.email).toEqual(fakeUser.email.toLowerCase())
|
||||
expect(user.role).toEqual('authenticated')
|
||||
expect(user.aud).toEqual('authenticated')
|
||||
// verify if metadata is correctly set after sing up
|
||||
expect(user.user_metadata).toEqual({
|
||||
username: username,
|
||||
date: date,
|
||||
})
|
||||
}
|
||||
|
||||
// steps
|
||||
|
||||
@step('Create Supabase client')
|
||||
private createSupaClient(
|
||||
url: string,
|
||||
key: string,
|
||||
options: SupabaseClientOptions = {}
|
||||
): SupabaseClient {
|
||||
return createClient(url, key, options)
|
||||
}
|
||||
|
||||
@step('Create a valid user')
|
||||
private async createUser(data: object = {}): Promise<{
|
||||
email: string
|
||||
password: string
|
||||
username: string
|
||||
}> {
|
||||
const supabase = this.createSupaClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY_ANON)
|
||||
|
||||
const fakeUser = {
|
||||
email: faker.internet.exampleEmail(),
|
||||
password: faker.internet.password(),
|
||||
username: faker.internet.userName(),
|
||||
}
|
||||
const { user, error: signUpError } = await this.signUp(supabase, fakeUser, {
|
||||
data: data,
|
||||
})
|
||||
expect(signUpError).toBeNull()
|
||||
|
||||
const [{ confirmation_token: token }] = await this.getConfirmationToken(user)
|
||||
|
||||
await this.verify(token)
|
||||
|
||||
return fakeUser
|
||||
}
|
||||
|
||||
@step((token: string) => `verify with token ${token}`)
|
||||
private async verify(token: string): Promise<Response> {
|
||||
return crossFetch(`${process.env.SUPABASE_GOTRUE}/verify`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
type: 'signup',
|
||||
token: token,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@step((user: User) => `get confirmation token for user ${user.id}`)
|
||||
private async getConfirmationToken(user: User): Promise<[{ confirmation_token: any }]> {
|
||||
return Authentication.sql`
|
||||
select confirmation_token
|
||||
from auth.users
|
||||
where id = ${user.id}
|
||||
`
|
||||
}
|
||||
|
||||
@step('I sign up with a valid email and password')
|
||||
private async signUp(
|
||||
supabase: SupabaseClient,
|
||||
{
|
||||
email = faker.internet.exampleEmail(),
|
||||
password = faker.internet.password(),
|
||||
}: {
|
||||
email?: string
|
||||
password?: string
|
||||
} = {},
|
||||
options: {
|
||||
redirectTo?: string
|
||||
data?: object
|
||||
} = {}
|
||||
): Promise<{
|
||||
user: User
|
||||
session: Session
|
||||
error: ApiError
|
||||
}> {
|
||||
return supabase.auth.signUp(
|
||||
{
|
||||
email: email,
|
||||
password: password,
|
||||
},
|
||||
options
|
||||
)
|
||||
}
|
||||
|
||||
@step('I sign up with a valid email and password')
|
||||
private async signUpByPhone(
|
||||
supabase: SupabaseClient,
|
||||
{
|
||||
phone = faker.phone.phoneNumber(),
|
||||
password = faker.internet.password(),
|
||||
}: {
|
||||
phone?: string
|
||||
password?: string
|
||||
} = {},
|
||||
options: {
|
||||
redirectTo?: string
|
||||
data?: object
|
||||
} = {}
|
||||
): Promise<{
|
||||
user: User
|
||||
session: Session
|
||||
error: ApiError
|
||||
}> {
|
||||
return supabase.auth.signUp(
|
||||
{
|
||||
phone: phone,
|
||||
password: password,
|
||||
},
|
||||
options
|
||||
)
|
||||
}
|
||||
|
||||
@step('Check if I am being able to log out')
|
||||
private signOut(supabase: SupabaseClient): { error: any } | PromiseLike<{ error: any }> {
|
||||
return supabase.auth.signOut()
|
||||
}
|
||||
|
||||
@step('Get user data, if there is a logged in user')
|
||||
private getUser(supabase: SupabaseClient) {
|
||||
return supabase.auth.user()
|
||||
}
|
||||
|
||||
@step('Check if I am logged in by checking if I can insert my profile')
|
||||
private async insertProfile(
|
||||
supabase: SupabaseClient,
|
||||
user: User,
|
||||
fakeUser: {
|
||||
username: string
|
||||
}
|
||||
): Promise<{ data: any; error: any }> {
|
||||
return supabase
|
||||
.from('profiles')
|
||||
.insert({
|
||||
id: user.id,
|
||||
username: fakeUser.username,
|
||||
})
|
||||
.single()
|
||||
}
|
||||
|
||||
@step('Check if I am logged in by checking if I can get my profile')
|
||||
private async getUserProfile(supabase: SupabaseClient): Promise<{ data: any }> {
|
||||
return supabase.from('profiles').select().maybeSingle()
|
||||
}
|
||||
|
||||
@step((user: User) => `Get user by ID (${user.id}) from Supabase auth schema`)
|
||||
private async selectUser(user: User): Promise<[{ email: string }]> {
|
||||
return Authentication.sql`
|
||||
select
|
||||
email
|
||||
from auth.users
|
||||
where
|
||||
id = ${user.id}
|
||||
`
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import { Severity } from 'allure-js-commons'
|
||||
import { FEATURE } from '../templates/enums'
|
||||
|
||||
describe('authentication', () => {
|
||||
beforeEach(() => {
|
||||
reporter
|
||||
.description('Feature should work cool')
|
||||
.feature(FEATURE.AUTHENTICATION)
|
||||
reporter.severity(Severity.BLOCKER)
|
||||
reporter.step('setup actions', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
})
|
||||
|
||||
test('New users', () => {
|
||||
reporter.description('When user sign up then he should be logged in')
|
||||
|
||||
reporter.step('Create Supabase anonymous client', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('I sign up with a valid email and password', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('Check if I am logged in', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
})
|
||||
|
||||
test('Existing users', () => {
|
||||
reporter.description('When user is already signed up then he should be able to logged in')
|
||||
|
||||
reporter.step('Create a valid user', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('I sign in with a valid email and password', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('Check if I am logged in', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => {
|
||||
/* implement it here */
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Severity } from 'allure-js-commons'
|
||||
|
||||
import { FEATURE } from './enums'
|
||||
|
||||
describe('authentication', () => {
|
||||
beforeEach(() => {
|
||||
reporter
|
||||
.feature(FEATURE.AUTHENTICATION)
|
||||
reporter.severity(Severity.BLOCKER)
|
||||
})
|
||||
|
||||
test('New users', () => {
|
||||
reporter.description('When user sign up then he should be logged in')
|
||||
|
||||
reporter.step('Create Supabase anonymous client', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('I sign up with a valid email and password', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am logged in', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => { /* don't modify! */ })
|
||||
})
|
||||
|
||||
test('Existing users', () => {
|
||||
reporter.description('When user is already signed up then he should be able to logged in')
|
||||
|
||||
reporter.step('Create a valid user', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('I sign in with a valid email and password', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am logged in', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => { /* don't modify! */ })
|
||||
})
|
||||
})
|
||||
35
tests/features/templates/authentication.ts
Normal file
35
tests/features/templates/authentication.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Severity } from 'allure-js-commons'
|
||||
|
||||
import { FEATURE } from './enums'
|
||||
|
||||
describe('authentication', () => {
|
||||
beforeEach(() => {
|
||||
reporter
|
||||
.feature(FEATURE.AUTHENTICATION)
|
||||
reporter.severity(Severity.BLOCKER)
|
||||
})
|
||||
|
||||
test('New users', () => {
|
||||
reporter.description('When user sign up then he should be logged in')
|
||||
|
||||
reporter.step('Create Supabase anonymous client', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('I sign up with a valid email and password', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am logged in', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => { /* don't modify! */ })
|
||||
})
|
||||
|
||||
test('Existing users', () => {
|
||||
reporter.description('When user is already signed up then he should be able to logged in')
|
||||
|
||||
reporter.step('Create a valid user', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('I sign in with a valid email and password', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am logged in', () => { /* don't modify! */ })
|
||||
|
||||
reporter.step('Check if I am being able to log out', () => { /* don't modify! */ })
|
||||
})
|
||||
})
|
||||
@@ -1,119 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import {
|
||||
AllureReporterApi,
|
||||
jasmine_,
|
||||
registerAllureReporter
|
||||
} from 'jest-allure2-adapter';
|
||||
import { ContentType, Severity } from 'allure-js-commons';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type TestDecorator = (target: object, property: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
||||
export class JasmineAllureReporter implements jasmine_.CustomReporter {
|
||||
allure: AllureReporterApi;
|
||||
|
||||
constructor(allure: AllureReporterApi) {
|
||||
this.allure = allure;
|
||||
}
|
||||
|
||||
suiteStarted(suite?: jasmine_.CustomReporterResult): void {
|
||||
this.allure.startGroup(suite.description);
|
||||
// some actions here on suite started
|
||||
}
|
||||
|
||||
suiteDone(): void {
|
||||
// some actions here on suite end
|
||||
this.allure.endGroup();
|
||||
}
|
||||
|
||||
specStarted(spec: jasmine_.CustomReporterResult): void {
|
||||
this.allure.startTest(spec);
|
||||
// some actions here on test started
|
||||
}
|
||||
|
||||
specDone(spec: jasmine_.CustomReporterResult): void {
|
||||
// some actions here on spec end
|
||||
this.allure.endTest(spec);
|
||||
}
|
||||
}
|
||||
|
||||
registerAllureReporter(
|
||||
undefined,
|
||||
(allure) => new JasmineAllureReporter(allure)
|
||||
);
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
reporter: AllureReporterApi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAllure(): AllureReporterApi {
|
||||
if (!global.reporter) {
|
||||
throw new Error('Unable to find Allure implementation');
|
||||
}
|
||||
return global.reporter;
|
||||
}
|
||||
|
||||
export function step<T>(nameFn: string | ((arg: T) => string)): TestDecorator {
|
||||
return (target: object, propertyKey: string, descriptor: PropertyDescriptor) => {
|
||||
const original: object = descriptor.value;
|
||||
let callable: (args: T) => void = () => {/* */};
|
||||
|
||||
if (typeof original === 'function') {
|
||||
descriptor.value = function (...args: [T]) {
|
||||
try {
|
||||
const value: string = typeof nameFn === 'function' ? nameFn.apply(this, args) : nameFn;
|
||||
callable = () => getAllure().step(value, () => original.apply(this, args));
|
||||
// tslint:disable-next-line:no-console
|
||||
console.info(`Step: ${value || nameFn}`);
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.error(`[ERROR] Failed to apply decorator: ${e}`);
|
||||
}
|
||||
return callable.apply(this, args);
|
||||
};
|
||||
}
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
export function attachment<T>(name: string, type: ContentType) {
|
||||
return (_target: object, _propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
|
||||
const original: object = descriptor.value;
|
||||
let callable: (args: T) => void = () => {/* */};
|
||||
|
||||
if (typeof original === 'function') {
|
||||
descriptor.value = async function (...args: [T]) {
|
||||
try {
|
||||
const content: Buffer | string = await original.apply(this, args);
|
||||
callable = () => getAllure().step(name, () => {
|
||||
getAllure().attachment(type.toString(), content, type);
|
||||
});
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.error(`[ERROR] Failed to apply decorator: ${e}`);
|
||||
}
|
||||
return callable.apply(this, args);
|
||||
};
|
||||
}
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
export function attach(name: string, content: string | Buffer, type: ContentType): void {
|
||||
getAllure().step(name, () => {
|
||||
getAllure().attachment(type.toString(), content, type);
|
||||
});
|
||||
}
|
||||
|
||||
export function log(name: string, description?: string): void {
|
||||
console.info(description ? `${name}: ${description}` : name);
|
||||
getAllure().step(name, () => {
|
||||
if (description) {
|
||||
getAllure().step(description, () => { /* */ });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
process.env.SUPABASE_URL = 'http://localhost:8000'
|
||||
process.env.SUPABASE_KEY_ANON =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE'
|
||||
process.env.SUPABASE_KEY_ADMIN =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q'
|
||||
@@ -1,18 +1,17 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from '@jest/types'
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
preset: 'ts-jest',
|
||||
transform: {
|
||||
'^.+\\.ts?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'cjs', 'json', 'node',],
|
||||
moduleFileExtensions: ['ts', 'js', 'cjs', 'json', 'node'],
|
||||
// globalSetup: './test/hooks.ts',
|
||||
// globalTeardown: './teardown.js',
|
||||
setupFilesAfterEnv: [
|
||||
'./jest-custom-reporter.ts',
|
||||
],
|
||||
// setupFilesAfterEnv: ['jest-allure2-adapter/dist/setup-default',],
|
||||
testTimeout: 25000,
|
||||
setupFiles: ['<rootDir>/.jest/jest-env.js'],
|
||||
setupFilesAfterEnv: ['<rootDir>/.jest/jest-custom-reporter.ts'],
|
||||
testRunner: 'jest-jasmine2',
|
||||
testTimeout: 5000,
|
||||
// testEnvironmentOptions: {
|
||||
// jiraUrl: ""
|
||||
// },
|
||||
@@ -24,5 +23,5 @@ const config: Config.InitialOptions = {
|
||||
statements: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
}
|
||||
export default config
|
||||
|
||||
172
tests/package-lock.json
generated
172
tests/package-lock.json
generated
@@ -9,15 +9,18 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^6.1.2",
|
||||
"@testdeck/jest": "^0.2.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"allure-commandline": "^2.17.2",
|
||||
"allure-js-commons": "^2.0.0-beta.14",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"eslint": "^8.7.0",
|
||||
"faker": "^6.6.6",
|
||||
"jest": "^27.4.7",
|
||||
"jest-allure2-adapter": "^0.3.11",
|
||||
"postgres": "^3.0.5",
|
||||
"ts-jest": "^27.1.3"
|
||||
}
|
||||
},
|
||||
@@ -646,6 +649,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@faker-js/faker": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-6.1.2.tgz",
|
||||
"integrity": "sha512-QSvmexHCxeRUk1/yKmoEDaWB5Hohjvtim5g2JJwy8S/l0L4b3y/GxSpE6vN4SBoVGGahEQW21uqyRr7EofI35A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz",
|
||||
@@ -984,6 +997,21 @@
|
||||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@testdeck/core": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@testdeck/core/-/core-0.2.0.tgz",
|
||||
"integrity": "sha512-2BAzKS18I+nFUb9kH2zK7Bs1CBD0WqaYikaLm+gRaOiQKYa8flvVzqlUGwjyOMmD16JFksgxYml4/7xm4tfEYA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@testdeck/jest": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@testdeck/jest/-/jest-0.2.0.tgz",
|
||||
"integrity": "sha512-YS8RupTg1Sb5TLkRGALppsI0iX8/LMDieRvPN0WGuJ+22zDugMXBBzN43X60pO+9HQ343qLUNzoV7RfQHHTQ+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@testdeck/core": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tootallnate/once": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
||||
@@ -1841,6 +1869,15 @@
|
||||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
|
||||
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"node-fetch": "2.6.7"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@@ -2420,12 +2457,6 @@
|
||||
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/faker": {
|
||||
"version": "6.6.6",
|
||||
"resolved": "https://registry.npmjs.org/faker/-/faker-6.6.6.tgz",
|
||||
"integrity": "sha512-9tCqYEDHI5RYFQigXFwF1hnCwcWCOJl/hmll0lr5D2Ljjb0o4wphb69wikeJDz5qCEzXCoPvG6ss5SDP6IfOdg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -3985,6 +4016,48 @@
|
||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -4200,6 +4273,16 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.0.5.tgz",
|
||||
"integrity": "sha512-/9VVVRG+bzLc/AB6QukEV+SERra2IRduGd8PDz/ZGu+1PQ6+TgCQYvX87GtPfxcYW4XZ58cyurJojnphdazW1g==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/porsager"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
@@ -5621,6 +5704,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@faker-js/faker": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-6.1.2.tgz",
|
||||
"integrity": "sha512-QSvmexHCxeRUk1/yKmoEDaWB5Hohjvtim5g2JJwy8S/l0L4b3y/GxSpE6vN4SBoVGGahEQW21uqyRr7EofI35A==",
|
||||
"dev": true
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz",
|
||||
@@ -5892,6 +5981,21 @@
|
||||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"@testdeck/core": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@testdeck/core/-/core-0.2.0.tgz",
|
||||
"integrity": "sha512-2BAzKS18I+nFUb9kH2zK7Bs1CBD0WqaYikaLm+gRaOiQKYa8flvVzqlUGwjyOMmD16JFksgxYml4/7xm4tfEYA==",
|
||||
"dev": true
|
||||
},
|
||||
"@testdeck/jest": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@testdeck/jest/-/jest-0.2.0.tgz",
|
||||
"integrity": "sha512-YS8RupTg1Sb5TLkRGALppsI0iX8/LMDieRvPN0WGuJ+22zDugMXBBzN43X60pO+9HQ343qLUNzoV7RfQHHTQ+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@testdeck/core": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"@tootallnate/once": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
||||
@@ -6536,6 +6640,15 @@
|
||||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
|
||||
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-fetch": "2.6.7"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@@ -6963,12 +7076,6 @@
|
||||
"jest-message-util": "^27.4.6"
|
||||
}
|
||||
},
|
||||
"faker": {
|
||||
"version": "6.6.6",
|
||||
"resolved": "https://registry.npmjs.org/faker/-/faker-6.6.6.tgz",
|
||||
"integrity": "sha512-9tCqYEDHI5RYFQigXFwF1hnCwcWCOJl/hmll0lr5D2Ljjb0o4wphb69wikeJDz5qCEzXCoPvG6ss5SDP6IfOdg==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -8180,6 +8287,39 @@
|
||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"dev": true
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"dev": true
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -8341,6 +8481,12 @@
|
||||
"find-up": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"postgres": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.0.5.tgz",
|
||||
"integrity": "sha512-/9VVVRG+bzLc/AB6QukEV+SERra2IRduGd8PDz/ZGu+1PQ6+TgCQYvX87GtPfxcYW4XZ58cyurJojnphdazW1g==",
|
||||
"dev": true
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
|
||||
@@ -3,21 +3,26 @@
|
||||
"version": "1.0.0",
|
||||
"description": "These tests can be run with Docker.",
|
||||
"scripts": {
|
||||
"test:js": "node ./node_modules/.bin/cucumber-js tests/ -r tests/features/definitions"
|
||||
"test": "jest",
|
||||
"allure:generate": "rm -rf allure-report && node_modules/allure-commandline/bin/allure generate",
|
||||
"allure:serve": "node_modules/allure-commandline/bin/allure serve",
|
||||
"test:report": "npm run allure:generate && npm run allure:serve"
|
||||
},
|
||||
"author": "Supabase, Inc.",
|
||||
"license": "MIT",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^6.1.2",
|
||||
"@testdeck/jest": "^0.2.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"allure-commandline": "^2.17.2",
|
||||
"allure-js-commons": "^2.0.0-beta.14",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"eslint": "^8.7.0",
|
||||
"faker": "^6.6.6",
|
||||
"jest": "^27.4.7",
|
||||
"jest-allure2-adapter": "^0.3.11",
|
||||
"postgres": "^3.0.5",
|
||||
"ts-jest": "^27.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
37
tests/tsconfig.json
Normal file
37
tests/tsconfig.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"es6",
|
||||
"DOM"
|
||||
],
|
||||
"removeComments": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"*": [
|
||||
"node_modules/*",
|
||||
"./types/*"
|
||||
]
|
||||
},
|
||||
"typeRoots": [
|
||||
"./node_modules/@types/",
|
||||
"./node_modules/allure2-js-commons/dist/declarations/**/"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"compileOnSave": false
|
||||
}
|
||||
Reference in New Issue
Block a user