不要怂,就是干,撸起袖子干!

Commit 914279aa by papb

test(types): refactor adding `expect-type`

Closes #11829
1 parent 9634338d
...@@ -58,7 +58,6 @@ ...@@ -58,7 +58,6 @@
"cls-hooked": "^4.2.2", "cls-hooked": "^4.2.2",
"cross-env": "^7.0.2", "cross-env": "^7.0.2",
"delay": "^4.3.0", "delay": "^4.3.0",
"dtslint": "^3.6.4",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"esdoc": "^1.1.0", "esdoc": "^1.1.0",
"esdoc-ecmascript-proposal-plugin": "^1.0.0", "esdoc-ecmascript-proposal-plugin": "^1.0.0",
...@@ -67,6 +66,7 @@ ...@@ -67,6 +66,7 @@
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-jsdoc": "^20.4.0", "eslint-plugin-jsdoc": "^20.4.0",
"eslint-plugin-mocha": "^6.2.2", "eslint-plugin-mocha": "^6.2.2",
"expect-type": "^0.11.0",
"fs-jetpack": "^4.1.0", "fs-jetpack": "^4.1.0",
"husky": "^4.2.5", "husky": "^4.2.5",
"js-combinatorics": "^0.5.5", "js-combinatorics": "^0.5.5",
...@@ -185,7 +185,7 @@ ...@@ -185,7 +185,7 @@
"test-postgresn": "npm run test-postgres-native", "test-postgresn": "npm run test-postgres-native",
"test-mssql": "cross-env DIALECT=mssql npm test", "test-mssql": "cross-env DIALECT=mssql npm test",
"test-all": "npm run test-mariadb && npm run test-mysql && npm run test-sqlite && npm run test-postgres && npm run test-postgres-native && npm run test-mssql", "test-all": "npm run test-mariadb && npm run test-mysql && npm run test-sqlite && npm run test-postgres && npm run test-postgres-native && npm run test-mssql",
"test-typings": "tsc -b types/tsconfig.json && dtslint --expectOnly types/test", "test-typings": "tsc -b types/tsconfig.json && tsc -b types/test/tsconfig.json",
"cover": "rimraf coverage && npm run teaser && npm run cover-integration && npm run cover-unit && npm run merge-coverage", "cover": "rimraf coverage && npm run teaser && npm run cover-integration && npm run cover-unit && npm run merge-coverage",
"cover-integration": "cross-env COVERAGE=true nyc --reporter=lcovonly mocha -t 30000 --exit \"test/integration/**/*.test.js\" && node -e \"require('fs').renameSync('coverage/lcov.info', 'coverage/integration.info')\"", "cover-integration": "cross-env COVERAGE=true nyc --reporter=lcovonly mocha -t 30000 --exit \"test/integration/**/*.test.js\" && node -e \"require('fs').renameSync('coverage/lcov.info', 'coverage/integration.info')\"",
"cover-unit": "cross-env COVERAGE=true nyc --reporter=lcovonly mocha -t 30000 --exit \"test/unit/**/*.test.js\" && node -e \"require('fs').renameSync('coverage/lcov.info', 'coverage/unit.info')\"", "cover-unit": "cross-env COVERAGE=true nyc --reporter=lcovonly mocha -t 30000 --exit \"test/unit/**/*.test.js\" && node -e \"require('fs').renameSync('coverage/lcov.info', 'coverage/unit.info')\"",
......
import { expectTypeOf } from "expect-type";
import { QueryTypes, Sequelize, SyncOptions } from 'sequelize'; import { QueryTypes, Sequelize, SyncOptions } from 'sequelize';
import { User } from 'models/User'; import { User } from 'models/User';
...@@ -8,22 +9,18 @@ sequelize.afterBulkSync((options: SyncOptions) => { ...@@ -8,22 +9,18 @@ sequelize.afterBulkSync((options: SyncOptions) => {
}); });
async function test() { async function test() {
const rows: unknown[] = await sequelize expectTypeOf(
.query('SELECT * FROM `test`', { await sequelize.query('SELECT * FROM `test`', { type: QueryTypes.SELECT })
type: QueryTypes.SELECT, ).toEqualTypeOf<unknown[]>();
});
const [autoIncrementId, affectedRows] = await sequelize
.query('INSERT into test set test=1', {
type: QueryTypes.INSERT,
});
}
expectTypeOf(
await sequelize.query('INSERT into test set test=1', { type: QueryTypes.INSERT })
).toEqualTypeOf<[number, number]>();
}
sequelize.transaction<void>(async transaction => { sequelize.transaction<void>(async transaction => {
const rows = await sequelize expectTypeOf(
.query('SELECT * FROM `user`', { await sequelize.query('SELECT * FROM `user`', {
retry: { retry: {
max: 123, max: 123,
}, },
...@@ -31,12 +28,15 @@ sequelize.transaction<void>(async transaction => { ...@@ -31,12 +28,15 @@ sequelize.transaction<void>(async transaction => {
transaction, transaction,
logging: true, logging: true,
}) })
).toEqualTypeOf<User[]>();
}); });
sequelize.query('SELECT * FROM `user` WHERE status = $1', sequelize.query(
'SELECT * FROM `user` WHERE status = $1',
{ bind: ['active'], type: QueryTypes.SELECT } { bind: ['active'], type: QueryTypes.SELECT }
); );
sequelize.query('SELECT * FROM `user` WHERE status = $status', sequelize.query(
'SELECT * FROM `user` WHERE status = $status',
{ bind: { status: 'active' }, type: QueryTypes.SELECT } { bind: { status: 'active' }, type: QueryTypes.SELECT }
); );
import { expectTypeOf } from "expect-type";
import { Model, Op } from 'sequelize'; import { Model, Op } from 'sequelize';
class MyModel extends Model {} class MyModel extends Model {}
const grouped: Promise<{ [key: string]: number }> = MyModel.count({ group: 'tag' }); expectTypeOf(MyModel.count()).toEqualTypeOf<Promise<number>>();
const counted: Promise<number> = MyModel.count(); expectTypeOf(MyModel.count({ group: 'tag' })).toEqualTypeOf<Promise<{ [key: string]: number }>>();
const countedDistinct: Promise<number> = MyModel.count({ col: 'tag', distinct: true }); expectTypeOf(MyModel.count({ col: 'tag', distinct: true })).toEqualTypeOf<Promise<number>>();
expectTypeOf(MyModel.count({
const countedDistinctOnReader: Promise<number> = MyModel.count({ where: { updatedAt: { [Op.gte]: new Date() } }, useMaster: false }) where: {
updatedAt: {
[Op.gte]: new Date()
}
},
useMaster: false
})).toEqualTypeOf<Promise<number>>();
import { INTEGER, IntegerDataType, TINYINT } from 'sequelize'; import { expectTypeOf } from 'expect-type';
import { SmallIntegerDataType, SMALLINT, MEDIUMINT, MediumIntegerDataType, BigIntDataType, BIGINT } from '../lib/data-types'; import { DataTypes } from 'sequelize';
let tinyint: IntegerDataType; const { TINYINT, SMALLINT, MEDIUMINT, BIGINT, INTEGER } = DataTypes;
tinyint = TINYINT();
tinyint = new TINYINT();
tinyint = TINYINT.UNSIGNED.ZEROFILL();
tinyint = new TINYINT.UNSIGNED.ZEROFILL();
let smallint: SmallIntegerDataType; // TINYINT
smallint = SMALLINT(); expectTypeOf(TINYINT()).toEqualTypeOf<DataTypes.TinyIntegerDataType>();
smallint = new SMALLINT(); expectTypeOf(new TINYINT()).toEqualTypeOf<DataTypes.TinyIntegerDataType>();
smallint = SMALLINT.UNSIGNED.ZEROFILL(); expectTypeOf(TINYINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.TinyIntegerDataType>();
smallint = new SMALLINT.UNSIGNED.ZEROFILL(); expectTypeOf(new TINYINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.TinyIntegerDataType>();
let mediumint: MediumIntegerDataType; // SMALLINT
mediumint = MEDIUMINT(); expectTypeOf(SMALLINT()).toEqualTypeOf<DataTypes.SmallIntegerDataType>();
mediumint = new MEDIUMINT(); expectTypeOf(new SMALLINT()).toEqualTypeOf<DataTypes.SmallIntegerDataType>();
mediumint = MEDIUMINT.UNSIGNED.ZEROFILL(); expectTypeOf(SMALLINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.SmallIntegerDataType>();
mediumint = new MEDIUMINT.UNSIGNED.ZEROFILL(); expectTypeOf(new SMALLINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.SmallIntegerDataType>();
let int: IntegerDataType; // MEDIUMINT
int = INTEGER(); expectTypeOf(MEDIUMINT()).toEqualTypeOf<DataTypes.MediumIntegerDataType>();
int = new INTEGER(); expectTypeOf(new MEDIUMINT()).toEqualTypeOf<DataTypes.MediumIntegerDataType>();
int = INTEGER.UNSIGNED.ZEROFILL(); expectTypeOf(MEDIUMINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.MediumIntegerDataType>();
int = new INTEGER.UNSIGNED.ZEROFILL(); expectTypeOf(new MEDIUMINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.MediumIntegerDataType>();
let bigint: BigIntDataType; // BIGINT
bigint = BIGINT(); expectTypeOf(BIGINT()).toEqualTypeOf<DataTypes.BigIntDataType>();
bigint = new BIGINT(); expectTypeOf(new BIGINT()).toEqualTypeOf<DataTypes.BigIntDataType>();
bigint = BIGINT.UNSIGNED.ZEROFILL(); expectTypeOf(BIGINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.BigIntDataType>();
bigint = new BIGINT.UNSIGNED.ZEROFILL(); expectTypeOf(new BIGINT.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.BigIntDataType>();
// INTEGER
expectTypeOf(INTEGER()).toEqualTypeOf<DataTypes.IntegerDataType>();
expectTypeOf(new INTEGER()).toEqualTypeOf<DataTypes.IntegerDataType>();
expectTypeOf(INTEGER.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.IntegerDataType>();
expectTypeOf(new INTEGER.UNSIGNED.ZEROFILL()).toEqualTypeOf<DataTypes.IntegerDataType>();
import { expectTypeOf } from 'expect-type';
import { BuildOptions, DataTypes, Model, Optional } from 'sequelize'; import { BuildOptions, DataTypes, Model, Optional } from 'sequelize';
import { sequelize } from './connection'; import { sequelize } from './connection';
...@@ -12,9 +13,7 @@ interface UserAttributes { ...@@ -12,9 +13,7 @@ interface UserAttributes {
interface UserCreationAttributes extends Optional<UserAttributes, 'id'> {} interface UserCreationAttributes extends Optional<UserAttributes, 'id'> {}
interface UserModel interface UserModel extends Model<UserAttributes, UserCreationAttributes>, UserAttributes {}
extends Model<UserAttributes, UserCreationAttributes>,
UserAttributes {}
const User = sequelize.define<UserModel>( const User = sequelize.define<UserModel>(
'User', 'User',
...@@ -28,14 +27,14 @@ const User = sequelize.define<UserModel>( ...@@ -28,14 +27,14 @@ const User = sequelize.define<UserModel>(
); );
async function test() { async function test() {
const user: UserModel = new User() as UserModel; expectTypeOf<UserModel>().toMatchTypeOf(new User());
const user2: UserModel | null = await User.findOne(); const user = await User.findOne();
if (!user2) return; expectTypeOf(user).toEqualTypeOf<UserModel | null>();
user2.firstName = 'John'; if (!user) return;
user.firstName = 'John';
await user2.save(); await user.save();
} }
// The below doesn't define Attribute types, but should still work // The below doesn't define Attribute types, but should still work
...@@ -61,12 +60,12 @@ UntypedUser.customStaticMethod = () => {}; ...@@ -61,12 +60,12 @@ UntypedUser.customStaticMethod = () => {};
async function testUntyped() { async function testUntyped() {
UntypedUser.customStaticMethod(); UntypedUser.customStaticMethod();
const user: UntypedUserModel = new UntypedUser() as UntypedUserModel; expectTypeOf<UntypedUserModel>().toMatchTypeOf(new UntypedUser());
const user2: UntypedUserModel | null = await UntypedUser.findOne();
if (!user2) return;
user2.firstName = 'John'; const user = await UntypedUser.findOne();
expectTypeOf(user).toEqualTypeOf<UntypedUserModel | null>();
await user2.save(); if (!user) return;
user.firstName = 'John';
await user.save();
} }
// Error === BaseError import { expectTypeOf } from "expect-type";
import { BaseError, EmptyResultError, Error, UniqueConstraintError } from 'sequelize'; import { BaseError, EmptyResultError, Error as AliasedBaseError, UniqueConstraintError } from 'sequelize';
import { User } from './models/User';
import { OptimisticLockError } from '../lib/errors'; import { OptimisticLockError } from '../lib/errors';
async function test() { expectTypeOf<AliasedBaseError>().toEqualTypeOf<BaseError>();
try { expectTypeOf<UniqueConstraintError>().toHaveProperty('sql').toBeString();
await User.create({ username: 'john_doe', firstName: 'John' }); expectTypeOf<EmptyResultError>().toMatchTypeOf<BaseError>();
} catch (e) { expectTypeOf<UniqueConstraintError>().toMatchTypeOf<BaseError>();
if (e instanceof UniqueConstraintError) { expectTypeOf<OptimisticLockError>().toMatchTypeOf<BaseError>();
throw new Error((e as UniqueConstraintError).sql);
}
}
try {
await User.findOne({
rejectOnEmpty: true,
where: {
username: 'something_that_doesnt_exist',
},
});
} catch (e) {
if (!(e instanceof EmptyResultError)) {
throw new Error('should return emptyresulterror');
}
}
class CustomError extends Error {}
try {
await User.findOne({
rejectOnEmpty: new CustomError('User does not exist'),
where: {
username: 'something_that_doesnt_exist',
},
});
} catch (e) {
if (!(e instanceof CustomError)) {
throw new Error('should return CustomError');
}
if (e.message !== 'User does not exist') {
throw new Error('should return CustomError with the proper message')
}
}
try {
const user: User | null = await User.findByPk(1);
if (user != null) {
user.username = 'foo';
user.save();
}
} catch (e) {
if (!(e instanceof OptimisticLockError)) {
throw new Error('should return OptimisticLockError');
}
}
}
import { User } from "./models/User"; import { User } from "./models/User";
User.findOne({ where: { firstName: 'John' }}); User.findOne({ where: { firstName: 'John' } });
// The below line should be an error if uncommented, thanks to the new // @ts-expect-error
// TAttributes-based typechecking User.findOne({ where: { blah: 'blah2' } });
// User.findOne({ where: { blah: 'blah2' }});
// Controls typescript version for testing the types
// TypeScript Version: 3.6
import { expectTypeOf } from "expect-type";
import { Association, BelongsToManyGetAssociationsMixin, DataTypes, HasOne, Model, Sequelize } from 'sequelize'; import { Association, BelongsToManyGetAssociationsMixin, DataTypes, HasOne, Model, Sequelize } from 'sequelize';
expectTypeOf<HasOne>().toMatchTypeOf<Association>();
class MyModel extends Model { class MyModel extends Model {
public num!: number; public num!: number;
public static associations: { public static associations: {
...@@ -12,10 +14,9 @@ class MyModel extends Model { ...@@ -12,10 +14,9 @@ class MyModel extends Model {
class OtherModel extends Model {} class OtherModel extends Model {}
const assoc: Association = MyModel.associations.other;
const Instance: MyModel = new MyModel({ int: 10 }); const Instance: MyModel = new MyModel({ int: 10 });
const num: number = Instance.get('num');
expectTypeOf(Instance.get('num')).toEqualTypeOf<number>();
MyModel.findOne({ MyModel.findOne({
include: [ include: [
...@@ -102,7 +103,7 @@ UserModel.findCreateFind({ ...@@ -102,7 +103,7 @@ UserModel.findCreateFind({
* Tests for findOrCreate() type. * Tests for findOrCreate() type.
*/ */
UserModel.findOrCreate({ UserModel.findOrCreate({
fields: [ "jane.doe" ], fields: [ "jane.doe" ],
where: { where: {
username: "jane.doe" username: "jane.doe"
...@@ -122,13 +123,13 @@ TestModel.primaryKeyAttributes; ...@@ -122,13 +123,13 @@ TestModel.primaryKeyAttributes;
* Test for joinTableAttributes on BelongsToManyGetAssociationsMixin * Test for joinTableAttributes on BelongsToManyGetAssociationsMixin
*/ */
class SomeModel extends Model { class SomeModel extends Model {
public getOthers!: BelongsToManyGetAssociationsMixin<OtherModel> public getOthers!: BelongsToManyGetAssociationsMixin<OtherModel>
} }
const someInstance = new SomeModel() const someInstance = new SomeModel();
someInstance.getOthers({ someInstance.getOthers({
joinTableAttributes: { include: [ 'id' ] } joinTableAttributes: { include: ['id'] }
}) });
/** /**
* Test for through options in creating a BelongsToMany association * Test for through options in creating a BelongsToMany association
...@@ -142,11 +143,11 @@ Film.belongsToMany(Actor, { ...@@ -142,11 +143,11 @@ Film.belongsToMany(Actor, {
model: 'FilmActors', model: 'FilmActors',
paranoid: true paranoid: true
} }
}) });
Actor.belongsToMany(Film, { Actor.belongsToMany(Film, {
through: { through: {
model: 'FilmActors', model: 'FilmActors',
paranoid: true paranoid: true
} }
}) });
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!