Skip to content

test(types): introduce tstyche instead of tsd #633

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
849 changes: 19 additions & 830 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"test:run": "jest --runInBand --coverage",
"test:generated-types": "run-s db:generate-test-types && git diff --exit-code test/types.generated.ts || (echo '❌ Generated types are not up to date. Run npm run db:generate-test-types.' && exit 1)",
"test:update": "run-s db:clean db:run db:generate-test-types && jest --runInBand --updateSnapshot && run-s db:clean",
"test:types": "run-s build && tsd --files 'test/**/*.test*.ts'",
"test:types": "run-s build && tstyche",
"test:types:watch": "chokidar 'src/**/*.ts' 'test/**/*.ts' -c 'npm run test:types'",
"type-check": "tsc --noEmit --project tsconfig.json",
"type-check:test": "tsc --noEmit --project tsconfig.test.json",
Expand All @@ -64,7 +64,7 @@
"semantic-release-plugin-update-version-in-files": "^1.1.0",
"ts-expect": "^1.3.0",
"ts-jest": "^28.0.3",
"tsd": "^0.31.2",
"tstyche": "^4.3.0",
"type-fest": "^4.32.0",
"typedoc": "^0.22.16",
"typescript": "^4.5.5",
Expand Down
10 changes: 5 additions & 5 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ test('throwOnError throws errors instead of returning them', async () => {
let isErrorCaught = false

try {
// @ts-expect-error: nonexistent table
// @ts-expect-error Argument of type '"missing_table"' is not assignable to parameter
await postgrest.from('missing_table').select().throwOnError()
} catch (error) {
expect(error).toMatchInlineSnapshot(
Expand All @@ -914,7 +914,7 @@ test('throwOnError throws errors instead of returning them', async () => {

test('throwOnError throws errors which include stack', async () => {
try {
// @ts-expect-error: nonexistent table
// @ts-expect-error Argument of type '"does_not_exist"' is not assignable to parameter
await postgrest.from('does_not_exist').select().throwOnError()
} catch (err) {
expect(err instanceof Error).toBe(true)
Expand All @@ -927,7 +927,7 @@ test('throwOnError throws errors which include stack', async () => {
// const postgrest_ = new PostgrestClient<Database>(REST_URL, { throwOnError: true })

// try {
// // @ts-expect-error missing table
// // @ts-expect-error! missing table
// await postgrest_.from('missing_table').select()
// } catch (error) {
// expect(error).toMatchInlineSnapshot()
Expand All @@ -942,7 +942,7 @@ test('throwOnError throws errors which include stack', async () => {
// const postgrest_ = new PostgrestClient<Database>(REST_URL, { throwOnError: true })

// try {
// // @ts-expect-error missing function
// // @ts-expect-error! missing function
// await postgrest_.rpc('missing_fn').select()
// } catch (error) {
// expect(error).toMatchInlineSnapshot()
Expand All @@ -955,7 +955,7 @@ test('throwOnError throws errors which include stack', async () => {
// test('throwOnError can be disabled per call', async () => {
// let isErrorCaught = false
// const postgrest_ = new PostgrestClient<Database>(REST_URL, { throwOnError: true })
// // @ts-expect-error missing table
// // @ts-expect-error! missing table
// const { error } = await postgrest_.from('missing_table').select().throwOnError(false)

// expect(error).toMatchInlineSnapshot()
Expand Down
68 changes: 36 additions & 32 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TypeEqual } from 'ts-expect'
import { expectError, expectType } from 'tsd'
import { expectType } from './types'
import { PostgrestClient, PostgrestError } from '../src/index'
import { Prettify } from '../src/types'
import { Json } from '../src/select-query-parser/types'
Expand All @@ -12,48 +12,50 @@ const postgrestWithOptions = new PostgrestClient<DatabaseWithOptions>(REST_URL)

// table invalid type
{
expectError(postgrest.from(42))
expectError(postgrest.from('nonexistent_table'))
// @ts-expect-error Argument of type '42' is not assignable to parameter of type
postgrest.from(42)
// @ts-expect-error Argument of type '"nonexistent_table"' is not assignable to parameter of type
postgrest.from('nonexistent_table')
}

// `null` can't be used with `.eq()`
{
postgrest.from('users').select().eq('username', 'foo')
expectError(postgrest.from('users').select().eq('username', null))
// @ts-expect-error Argument of type 'null' is not assignable to parameter of type 'string'
postgrest.from('users').select().eq('username', null)

const nullableVar = 'foo' as string | null
expectError(postgrest.from('users').select().eq('username', nullableVar))
// @ts-expect-error Argument of type 'string | null' is not assignable to parameter of type 'string'
postgrest.from('users').select().eq('username', nullableVar)
}

// `.eq()`, '.neq()' and `.in()` validate provided filter value when column is an enum.
// Behaves the same for simple columns, as well as relationship filters.
{
expectError(postgrest.from('users').select().eq('status', 'invalid'))
expectError(postgrest.from('users').select().neq('status', 'invalid'))
expectError(postgrest.from('users').select().in('status', ['invalid']))
// @ts-expect-error Argument of type '"invalid"' is not assignable to parameter of type '"ONLINE" | "OFFLINE"'
postgrest.from('users').select().eq('status', 'invalid')
// @ts-expect-error Argument of type '"invalid"' is not assignable to parameter of type '"ONLINE" | "OFFLINE" | null'
postgrest.from('users').select().neq('status', 'invalid')
// @ts-expect-error Type '"invalid"' is not assignable to type '"ONLINE" | "OFFLINE" | null'
postgrest.from('users').select().in('status', ['invalid'])

// @ts-expect-error Argument of type '"invalid"' is not assignable to parameter of type '"ONLINE" | "OFFLINE"'
postgrest.from('best_friends').select('users!first_user(status)').eq('users.status', 'invalid')
// @ts-expect-error Argument of type '"invalid"' is not assignable to parameter of type '"ONLINE" | "OFFLINE" | null'
postgrest.from('best_friends').select('users!first_user(status)').neq('users.status', 'invalid')
postgrest
.from('best_friends')
.select('users!first_user(status)')
// @ts-expect-error Type '"invalid"' is not assignable to type '"ONLINE" | "OFFLINE" | null'
.in('users.status', ['invalid'])

expectError(
postgrest.from('best_friends').select('users!first_user(status)').eq('users.status', 'invalid')
)
expectError(
postgrest.from('best_friends').select('users!first_user(status)').neq('users.status', 'invalid')
)
expectError(
postgrest
.from('best_friends')
.select('users!first_user(status)')
.in('users.status', ['invalid'])
)
// Validate deeply nested embedded tables
expectError(
postgrest.from('users').select('messages(channels(*))').eq('messages.channels.id', 'invalid')
)
expectError(
postgrest.from('users').select('messages(channels(*))').neq('messages.channels.id', 'invalid')
)
expectError(
postgrest.from('users').select('messages(channels(*))').in('messages.channels.id', ['invalid'])
)
// @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'number'
postgrest.from('users').select('messages(channels(*))').eq('messages.channels.id', 'invalid')
// @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'number'
postgrest.from('users').select('messages(channels(*))').neq('messages.channels.id', 'invalid')
// @ts-expect-error Type 'string' is not assignable to type 'number'
postgrest.from('users').select('messages(channels(*))').in('messages.channels.id', ['invalid'])

{
const result = await postgrest.from('users').select('status').eq('status', 'ONLINE')
Expand Down Expand Up @@ -147,12 +149,14 @@ const postgrestWithOptions = new PostgrestClient<DatabaseWithOptions>(REST_URL)

// cannot update non-updatable views
{
expectError(postgrest.from('updatable_view').update({ non_updatable_column: 0 }))
// @ts-expect-error Type 'number' is not assignable to type 'undefined'
postgrest.from('updatable_view').update({ non_updatable_column: 0 })
}

// cannot update non-updatable columns
{
expectError(postgrest.from('updatable_view').update({ non_updatable_column: 0 }))
// @ts-expect-error Type 'number' is not assignable to type 'undefined'
postgrest.from('updatable_view').update({ non_updatable_column: 0 })
}

// spread resource with single column in select query
Expand Down Expand Up @@ -300,6 +304,6 @@ const postgrestWithOptions = new PostgrestClient<DatabaseWithOptions>(REST_URL)
// Check that client options __InternalSupabase isn't considered like the other schemas
{
await postgrestWithOptions
// @ts-expect-error supabase internal shouldn't be available as one of the selectable schema
// @ts-expect-error Argument of type '"__InternalSupabase"' is not assignable to parameter of type '"personal" | "public"'
.schema('__InternalSupabase')
}
2 changes: 1 addition & 1 deletion test/issue-1354-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expectType } from 'tsd'
import { expectType } from './types'
import { PostgrestClient } from '../src/index'
import type { MergeDeep } from 'type-fest'

Expand Down
6 changes: 3 additions & 3 deletions test/max-affected.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { Database as DatabasePostgrest13 } from './types.override-with-options-postgrest13'
import { expectType } from 'tsd'
import { expectType } from './types'
import { InvalidMethodError } from '../src/PostgrestFilterBuilder'
import { z } from 'zod'
import { RequiredDeep } from 'type-fest'
Expand Down Expand Up @@ -60,11 +60,11 @@ describe('maxAffected', () => {
resUpsert
)
expectType<InvalidMethodError<'maxAffected method only available on update or delete'>>(
// @ts-expect-error update method shouldn't return an error
//@ts-expect-error InvalidMethodError<"maxAffected method only available on update or delete">
resUpdate
)
expectType<InvalidMethodError<'maxAffected method only available on update or delete'>>(
// @ts-expect-error delete method shouldn't return an error
// @ts-expect-error InvalidMethodError<"maxAffected method only available on update or delete">
resDelete
)
})
Expand Down
2 changes: 1 addition & 1 deletion test/override-types.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { PostgrestClient } from '../src'
import { CustomUserDataType, Database } from './types.override'
Expand Down
2 changes: 1 addition & 1 deletion test/relationships-aggregate-operations.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'

Expand Down
3 changes: 1 addition & 2 deletions test/relationships-error-handling.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { SelectQueryError } from '../src/select-query-parser/utils'

const REST_URL = 'http://localhost:3000'
export const postgrest = new PostgrestClient<Database>(REST_URL)
const userColumn: 'catchphrase' | 'username' = 'username'

test('join over a 1-1 relation with both nullables and non-nullables fields with no hinting', async () => {
const res = await postgrest
Expand Down
2 changes: 1 addition & 1 deletion test/relationships-join-operations.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PostgrestClient } from '../src/index'
import { Database, CustomUserDataTypeSchema } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'
import { RequiredDeep } from 'type-fest'
Expand Down
2 changes: 1 addition & 1 deletion test/relationships-spread-operations.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { Database as DatabaseWithOptions13 } from './types.override-with-options-postgrest13'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'

Expand Down
2 changes: 1 addition & 1 deletion test/relationships.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PostgrestClient } from '../src/index'
import { CustomUserDataTypeSchema, Database } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'
import { Json } from '../src/select-query-parser/types'
Expand Down
2 changes: 1 addition & 1 deletion test/resource-embedding.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'
import { RequiredDeep } from 'type-fest'
Expand Down
2 changes: 1 addition & 1 deletion test/returns.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expectType } from 'tsd'
import { expectType } from './types'
import { PostgrestBuilder, PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { TypeEqual } from 'ts-expect'
Expand Down
2 changes: 1 addition & 1 deletion test/rpc.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PostgrestClient } from '../src/index'
import { Database } from './types.override'
import { expectType } from 'tsd'
import { expectType } from './types'
import { TypeEqual } from 'ts-expect'
import { z } from 'zod'

Expand Down
2 changes: 1 addition & 1 deletion test/select-query-parser/default-inference.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PostgrestClient } from '../../src/index'
import { expectType } from 'tsd'
import { expectType } from '../types'
import { TypeEqual } from 'ts-expect'

const REST_URL = 'http://localhost:3000'
Expand Down
2 changes: 1 addition & 1 deletion test/select-query-parser/parser.test-d.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups.. Take a look lines 529 and 537. expectType() must be used there instead of expect(). Seems like Jest’s global types are leaking.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expectType } from 'tsd'
import { expectType } from '../types'
import type { ParseQuery, ParserError } from '../../src/select-query-parser/parser'

// This test file is here to ensure some of our perser behave as expected
Expand Down
2 changes: 1 addition & 1 deletion test/select-query-parser/types.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expectType } from 'tsd'
import { expectType } from '../types'
import { TypeEqual } from 'ts-expect'
import { DeduplicateRelationships, GetComputedFields } from '../../src/select-query-parser/utils'
import { Database } from '../types.generated'
Expand Down
5 changes: 5 additions & 0 deletions test/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect } from 'tstyche'

export function expectType<T>(expression: T) {
return expect(expression).type.toBe<T>()
}
6 changes: 6 additions & 0 deletions tstyche.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://tstyche.org/schemas/config.json",
"testFileMatch": ["./test/**/*.test.ts", "./test/**/*.test-d.ts"],
"checkSuppressedErrors": true,
"tsconfig": "./tsconfig.test.json"
}