diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 3b694a3d..733146fb 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -2,7 +2,6 @@ name: Tests on: pull_request: branches: - - main push: branches: - main diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 00000000..29aee9b9 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,23 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "ignorePatterns": [ + "dist/**", + "coverage/**" + ], + "categories": { + "correctness": "error", + "suspicious": "error" + }, + "rules": { + "eslint/no-new": "off", + "eslint/no-shadow": "off", + "eslint/no-underscore-dangle": "off", + "eslint/no-useless-constructor": "off", + "unicorn/no-array-sort": "off", + "unicorn/no-useless-spread": "off", + "typescript/consistent-type-definitions": [ + "error", + "interface" + ] + } +} diff --git a/DEVGUIDE.md b/DEVGUIDE.md index cd769018..9cff89a3 100644 --- a/DEVGUIDE.md +++ b/DEVGUIDE.md @@ -36,10 +36,15 @@ DATA_API_PASSWORD=cassandra npm run test ``` +To run a subset of tests, pass a name pattern: +```shell +npm test -- -g "pattern" +``` + ### Lint -Run `npm run lint` to run ESLint. -ESLint will point out any formatting and code quality issues it finds. -ESLint can automatically fix some issues: run `npm run lint -- --fix` to tell ESLint to automatically fix what issues it can. +Run `npm run lint` to run oxlint. +oxlint will point out code quality issues it finds. +oxlint can automatically fix some issues: run `npm run lint -- --fix` to tell oxlint to automatically fix what issues it can. You should try to run `npm run lint` before committing to minimize risk of regressions. ## Update Stargate and Data API versions diff --git a/bin/run-tests.ts b/bin/run-tests.ts new file mode 100644 index 00000000..891d04ca --- /dev/null +++ b/bin/run-tests.ts @@ -0,0 +1,33 @@ +import { spawnSync } from 'child_process'; + +const args = process.argv.slice(2); +const nodeOptions: string[] = []; +const testFiles: string[] = []; + +for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + if (arg === '-g' || arg === '--grep') { + nodeOptions.push(`--test-name-pattern=${args[++i]}`); + } else if (arg === '--test-name-pattern' && args[i + 1] != null) { + nodeOptions.push(`${arg}=${args[++i]}`); + } else if (arg.startsWith('-')) { + nodeOptions.push(arg); + } else { + testFiles.push(arg); + } +} + +const result = spawnSync(process.execPath, [ + '--import=tsx', + '--test', + '--test-concurrency=1', + ...nodeOptions, + ...testFiles +], { stdio: 'inherit' }); + +if (result.error) { + throw result.error; +} + +process.exitCode = result.status ?? 1; diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 23173178..00000000 --- a/eslint.config.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -const globals = require('globals'); -const eslint = require('@eslint/js'); -const tseslint = require('typescript-eslint'); - -module.exports = [ - { - ignores: ['dist/**', 'coverage'] - }, - { - languageOptions: { - ecmaVersion: 2020, - globals: { - ...globals.node - } - }, - files: [ - 'src/**/*.ts', - 'tests/**/*.ts' - ] - }, - { - ...eslint.configs.recommended, - files: [ - 'src/**/*.ts', - 'tests/**/*.ts' - ], - }, - ...tseslint.configs.recommended.map(config => ({ - ...config, - files: [ - 'src/**/*.ts', - 'tests/**/*.ts' - ], - })), - { - files: [ - 'src/**/*.ts', - 'tests/**/*.ts' - ], - rules: { - 'semi': 'error', - - // Warnings: style and readability concerns - 'indent': [ - 'warn', - 4 - ], - 'quotes': ['warn', 'single'], - 'prefer-const': 'warn', - 'no-extra-semi': 'warn', - 'no-trailing-spaces': 'warn', - 'no-dupe-keys': 'error', - 'no-unreachable': 'error', - '@typescript-eslint/consistent-type-definitions': ['error', 'interface'] - } - } -]; diff --git a/package.json b/package.json index 75c7e707..b904828f 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,6 @@ "license": "Apache-2.0", "main": "dist/index.js", "types": "dist/index.d.ts", - "mocha": { - "timeout": 30000 - }, "directories": { "lib": "src", "test": "tests", @@ -48,13 +45,13 @@ "url": "git+https://github.com/stargate/stargate-mongoose.git" }, "scripts": { - "lint": "eslint .", + "lint": "oxlint", "pretest": "touch .env", - "test": "env TEST_DOC_DB=dataapi node --env-file=.env ./node_modules/.bin/ts-mocha --forbid-only -p tsconfig.json tests/**/*.test.ts tests/*.test.ts", - "test-astra": "env TEST_DOC_DB=astra node --env-file=.env ./node_modules/.bin/nyc --check-coverage --reporter=text --reporter=lcov ts-mocha --forbid-only -p tsconfig.json tests/**/*.test.ts tests/*.test.ts", - "test-dataapi": "env TEST_DOC_DB=dataapi node --env-file=.env ./node_modules/.bin/nyc --check-coverage --reporter=text --reporter=lcov ts-mocha --forbid-only -p tsconfig.json tests/**/*.test.ts tests/*.test.ts", - "clean-db": "node --env-file=.env ./node_modules/.bin/ts-node --project tsconfig.json bin/clean-db.ts", - "warm-up-tests": "node --env-file=.env ./node_modules/.bin/ts-node --project tsconfig.json bin/warm-up-tests.ts", + "test": "env TEST_DOC_DB=dataapi tsx --env-file=.env bin/run-tests.ts tests/**/*.test.ts tests/*.test.ts", + "test-astra": "env TEST_DOC_DB=astra tsx --env-file=.env bin/run-tests.ts tests/**/*.test.ts tests/*.test.ts", + "test-dataapi": "env TEST_DOC_DB=dataapi tsx --env-file=.env bin/run-tests.ts tests/**/*.test.ts tests/*.test.ts", + "clean-db": "tsx --env-file=.env bin/clean-db.ts", + "warm-up-tests": "tsx --env-file=.env bin/warm-up-tests.ts", "preinstall": "npm run update-version-file", "build": "npm run update-version-file && tsc --project tsconfig.build.json", "build:test": "tsc", @@ -69,18 +66,16 @@ "@babel/core": "^7.18.2", "@babel/preset-env": "^7.18.2", "@babel/preset-typescript": "^7.17.12", - "@types/mocha": "^10.0.10", "@types/node": "^20.18.1", "@types/sinon": "^17.0.4", - "eslint": "^9.23.0", "jsdoc-babel": "^0.5.0", "jsdoc-to-markdown": "^9.1.1", "mongoose": "^9.1.0", "nyc": "^17.1.0", "sinon": "^16.1.1", - "ts-mocha": "^11.1.0", - "typescript": "~6.0", - "typescript-eslint": "^8.35.0" + "tsx": "^4.19.2", + "typescript": "~7.0", + "oxlint": "^1.76.0" }, "dependencies": { "@datastax/astra-db-ts": "^2.1.0" diff --git a/tests/collections/options.test.ts b/tests/collections/options.test.ts index d8356cd7..7b0cd822 100644 --- a/tests/collections/options.test.ts +++ b/tests/collections/options.test.ts @@ -14,11 +14,11 @@ import assert from 'assert'; import mongoose from 'mongoose'; +import { afterEach, before, beforeEach, describe, it } from 'node:test'; import { Product, ProductHydratedDoc, createMongooseCollections } from '../../tests/mongooseFixtures'; describe('Options tests', async () => { before(async function() { - this.timeout(120_000); await createMongooseCollections(false); }); diff --git a/tests/convertSchemaToColumns.test.ts b/tests/convertSchemaToColumns.test.ts index 6900bfba..fb435816 100644 --- a/tests/convertSchemaToColumns.test.ts +++ b/tests/convertSchemaToColumns.test.ts @@ -14,6 +14,7 @@ import { Mongoose, Schema as MongooseSchema } from 'mongoose'; import assert from 'assert'; +import { beforeEach, describe, it } from 'node:test'; import convertSchemaToColumns from '../src/convertSchemaToColumns'; import * as AstraMongooseDriver from '../src/driver'; diff --git a/tests/createAstraUri.test.ts b/tests/createAstraUri.test.ts index 56ca1acc..4aa2bdc8 100644 --- a/tests/createAstraUri.test.ts +++ b/tests/createAstraUri.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { describe, it } from 'node:test'; import createAstraUri from '../src/createAstraUri'; describe('Utils test', () => { diff --git a/tests/driver/collections.api.test.ts b/tests/driver/collections.api.test.ts index b95df779..5841f766 100644 --- a/tests/driver/collections.api.test.ts +++ b/tests/driver/collections.api.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { afterEach, before, beforeEach, describe, it } from 'node:test'; import { testClient, TEST_COLLECTION_NAME @@ -41,7 +42,6 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( let mongooseInstance: AstraMongoose; before(async function() { - this.timeout(120_000); ({ Product, Cart, mongooseInstance } = await createMongooseCollections(false)); }); @@ -235,7 +235,6 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( ); }); it('API ops tests db.dropCollection() and Model.createCollection()', async function() { - this.timeout(120_000); let collections = await Product.db.listCollections().then(collections => collections.map(coll => coll.name)); assert.ok(collections.includes(Product.collection.collectionName)); @@ -787,9 +786,9 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( const res = await mongooseInstance.connection.collection('products').findOne({}); assert.equal(res!.name, 'Product 1'); }); - it('API ops tests connection.listDatabases()', async function() { + it('API ops tests connection.listDatabases()', async function(t) { if (testClient!.isAstra) { - return this.skip(); + return t.skip(); } const { databases } = await mongooseInstance!.connection.listDatabases(); assert.ok(Array.isArray(databases)); @@ -1221,7 +1220,7 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( }); }); - describe('vectorize', function () { + describe('vectorize', { skip: !testClient!.isAstra }, function () { const vectorSchema = new Schema( { $vector: { type: [Number], default: () => void 0, dimension: 1024 }, @@ -1256,10 +1255,6 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( let Vector: Model>; before(async function() { - if (!testClient!.isAstra) { - return this.skip(); - } - mongooseInstance.deleteModel(/Vector/); Vector = mongooseInstance.model( 'Vector', @@ -1324,7 +1319,7 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( }); }); - describe('vectorize with select: true', function () { + describe('vectorize with select: true', { skip: !testClient!.isAstra }, function () { const vectorSchema = new Schema( { $vector: { type: [Number], default: () => void 0, dimension: 1024 }, @@ -1346,10 +1341,6 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( let Vector: Model>; before(async function() { - if (!testClient!.isAstra) { - return this.skip(); - } - mongooseInstance.deleteModel(/Vector/); Vector = mongooseInstance.model( 'Vector', @@ -1417,7 +1408,6 @@ describe('COLLECTIONS: mongoose Model API level tests with collections', async ( let LexicalModel: Model>; before(async function () { - this.timeout(120_000); await mongooseInstance.connection.dropCollection(TEST_COLLECTION_NAME); LexicalModel = mongooseInstance.model('Lexical', lexicalSchema, TEST_COLLECTION_NAME); diff --git a/tests/driver/collections.driver.test.ts b/tests/driver/collections.driver.test.ts index 4e1999fb..dacd48b9 100644 --- a/tests/driver/collections.driver.test.ts +++ b/tests/driver/collections.driver.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { after, before, describe, it } from 'node:test'; import mongoose from 'mongoose'; import sinon from 'sinon'; import * as AstraMongooseDriver from '../../src/driver'; @@ -27,7 +28,6 @@ describe('COLLECTIONS: driver based tests', async () => { let mongooseInstance: AstraMongoose; before(async function() { - this.timeout(120_000); ({ Product, Cart, mongooseInstance } = await createMongooseCollections(false)); }); diff --git a/tests/driver/tables.api.test.ts b/tests/driver/tables.api.test.ts index bc38aed6..845072b5 100644 --- a/tests/driver/tables.api.test.ts +++ b/tests/driver/tables.api.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { afterEach, before, describe, it } from 'node:test'; import { testClient } from '../fixtures'; @@ -778,8 +779,6 @@ describe('TABLES: Mongoose Model API level tests', async () => { let LexicalModel: mongoose.Model>; before(async function () { - this.timeout(120_000); - await mongooseInstance.connection.dropCollection(TEST_TABLE_NAME); LexicalModel = mongooseInstance.model('Lexical', lexicalSchema, TEST_TABLE_NAME); diff --git a/tests/driver/tables.driver.test.ts b/tests/driver/tables.driver.test.ts index dce10fb6..5d9f00a5 100644 --- a/tests/driver/tables.driver.test.ts +++ b/tests/driver/tables.driver.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { after, before, describe, it } from 'node:test'; import mongoose from 'mongoose'; import * as AstraMongooseDriver from '../../src/driver'; import { testClient, TEST_TABLE_NAME } from '../fixtures'; diff --git a/tests/driver/tables.test.ts b/tests/driver/tables.test.ts index c4229f35..2ef841cb 100644 --- a/tests/driver/tables.test.ts +++ b/tests/driver/tables.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { afterEach, before, beforeEach, describe, it } from 'node:test'; import { mongooseInstanceTables as mongooseInstance, createMongooseCollections, testDebug } from '../mongooseFixtures'; import mongoose, { Schema, Types } from 'mongoose'; import { randomUUID } from 'crypto'; diff --git a/tests/driver/tables.vector.test.ts b/tests/driver/tables.vector.test.ts index 7dc205b9..38347182 100644 --- a/tests/driver/tables.vector.test.ts +++ b/tests/driver/tables.vector.test.ts @@ -23,6 +23,7 @@ import { } from 'mongoose'; import { Vectorize } from '../../src/driver/vectorize'; import assert from 'assert'; +import { before, beforeEach, describe, it } from 'node:test'; import compareTableDefinitions from '../compareTableDefinitions'; import { testClient } from '../fixtures'; import { createMongooseCollections, mongooseInstanceTables as mongooseInstance, testDebug } from '../mongooseFixtures'; @@ -237,7 +238,7 @@ describe('TABLES: vector search', function() { }); }); -describe('TABLES: vectorize', function () { +describe('TABLES: vectorize', { skip: !testClient!.isAstra }, function () { interface IVector { vector: string | number[] | null; name?: string | null; @@ -259,10 +260,6 @@ describe('TABLES: vectorize', function () { }); before(async function() { - if (!testClient!.isAstra) { - return this.skip(); - } - mongooseInstance.deleteModel(/Vector/); Vector = mongooseInstance.model( 'Vector', diff --git a/tests/mongooseFixtures.ts b/tests/mongooseFixtures.ts index 0ef70ad0..5295d33d 100644 --- a/tests/mongooseFixtures.ts +++ b/tests/mongooseFixtures.ts @@ -16,6 +16,7 @@ import { testClient } from './fixtures'; import { Schema, Mongoose, InferSchemaType, SubdocsToPOJOs } from 'mongoose'; import * as AstraMongooseDriver from '../src/driver'; import assert from 'assert'; +import { after } from 'node:test'; import compareTableDefinitions from './compareTableDefinitions'; import { plugins } from '../src/driver'; import tableDefinitionFromSchema from '../src/tableDefinitionFromSchema'; @@ -175,5 +176,8 @@ export async function createMongooseCollections(isTable: boolean) { } after(async function disconnectMongooseFixtures() { - await mongooseInstance.disconnect(); + await Promise.all([ + mongooseInstance.disconnect(), + mongooseInstanceTables.disconnect() + ]); }); diff --git a/tests/parseUri.test.ts b/tests/parseUri.test.ts index 0fbbd378..3de316ed 100644 --- a/tests/parseUri.test.ts +++ b/tests/parseUri.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { describe, it } from 'node:test'; import { parseUri } from '../src/driver/connection'; describe('parseUri', () => { diff --git a/tests/serialize.test.ts b/tests/serialize.test.ts index 45cdbd22..e3dc3755 100644 --- a/tests/serialize.test.ts +++ b/tests/serialize.test.ts @@ -13,6 +13,7 @@ // limitations under the License. import assert from 'assert'; +import { describe, it } from 'node:test'; import { serialize } from '../src/serialize'; import { Types } from 'mongoose'; diff --git a/tests/tableDefinitionFromSchema.test.ts b/tests/tableDefinitionFromSchema.test.ts index c34eb756..66d172ce 100644 --- a/tests/tableDefinitionFromSchema.test.ts +++ b/tests/tableDefinitionFromSchema.test.ts @@ -14,6 +14,7 @@ import { Schema } from 'mongoose'; import assert from 'assert'; +import { describe, it } from 'node:test'; import tableDefinitionFromSchema from '../src/tableDefinitionFromSchema'; describe('tableDefinitionFromSchema', () => { diff --git a/tests/udt/convertSchemaToUDTColumns.test.ts b/tests/udt/convertSchemaToUDTColumns.test.ts index 8a5948c6..23add6d8 100644 --- a/tests/udt/convertSchemaToUDTColumns.test.ts +++ b/tests/udt/convertSchemaToUDTColumns.test.ts @@ -14,6 +14,7 @@ import { Schema } from 'mongoose'; import assert from 'assert'; +import { describe, it } from 'node:test'; import convertSchemaToUDTColumns from '../../src/udt/convertSchemaToUDTColumns'; describe('convertSchemaToUDTColumns', () => { diff --git a/tests/udt/udtDefinitionsFromSchema.test.ts b/tests/udt/udtDefinitionsFromSchema.test.ts index 1891526d..84d537f3 100644 --- a/tests/udt/udtDefinitionsFromSchema.test.ts +++ b/tests/udt/udtDefinitionsFromSchema.test.ts @@ -14,6 +14,7 @@ import { Schema } from 'mongoose'; import assert from 'assert'; +import { describe, it } from 'node:test'; import udtDefinitionsFromSchema from '../../src/udt/udtDefinitionsFromSchema'; describe('udtDefinitionsFromSchema', () => { diff --git a/tsconfig.json b/tsconfig.json index 4936907b..d7e1d79c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, - "types": ["node", "mocha"], + "types": ["node"], "skipLibCheck": true }, "include": ["tests/**/*", "src/**/*"]