diff --git a/example/src/screens/UnitTestScreen.tsx b/example/src/screens/UnitTestScreen.tsx index 84d79103..bf9eeb15 100644 --- a/example/src/screens/UnitTestScreen.tsx +++ b/example/src/screens/UnitTestScreen.tsx @@ -2,7 +2,10 @@ import React, { useEffect, useState } from 'react' import { ScrollView, Text } from 'react-native' import type { MochaTestResult } from '../tests/MochaSetup' import { runTests } from '../tests/MochaSetup' -import { registerUnitTests } from '../tests/unitTests.spec' +import { + registerUnitTests, + /* registerTypeORMUnitTests, */ +} from '../tests/unit' import { ScreenStyles } from '../styles' export function UnitTestScreen() { @@ -12,7 +15,7 @@ export function UnitTestScreen() { setResults([]) runTests( registerUnitTests, - // registerTypeORMTests + // registerTypeORMUnitTests ).then(setResults) }, []) diff --git a/example/src/tests/unit/common.ts b/example/src/tests/unit/common.ts new file mode 100644 index 00000000..4d78cba5 --- /dev/null +++ b/example/src/tests/unit/common.ts @@ -0,0 +1,35 @@ +import { Chance } from 'chance' +import { + NitroSQLiteConnection, + enableSimpleNullHandling, +} from 'react-native-nitro-sqlite' +import { testDb as testDbInternal, resetTestDb } from '../db' +import chai from 'chai' + +export function isError(e: unknown): e is Error { + return e instanceof Error +} + +export const expect = chai.expect +export const chance = new Chance() + +export let testDb: NitroSQLiteConnection + +export function setupTestDb() { + enableSimpleNullHandling(false) + + try { + resetTestDb() + + if (testDbInternal == null) throw new Error('Failed to reset test database') + + testDbInternal.execute('DROP TABLE IF EXISTS User;') + testDbInternal.execute( + 'CREATE TABLE User ( id REAL PRIMARY KEY, name TEXT NOT NULL, age REAL, networth REAL) STRICT;', + ) + + testDb = testDbInternal! + } catch (e) { + console.warn('Error resetting user database', e) + } +} diff --git a/example/src/tests/unit/index.ts b/example/src/tests/unit/index.ts new file mode 100644 index 00000000..7b8762c6 --- /dev/null +++ b/example/src/tests/unit/index.ts @@ -0,0 +1,20 @@ +import { beforeEach, describe } from '../MochaRNAdapter' +import { setupTestDb } from './common' +import registerExecuteUnitTests from './specs/execute.spec' +import registerTransactionUnitTests from './specs/transaction.spec' +import registerExecuteBatchUnitTests from './specs/executeBatch.spec' +import registerTypeORMUnitTestsSpecs from './specs/typeorm.spec' + +export function registerUnitTests() { + beforeEach(setupTestDb) + + describe('Operations', () => { + registerExecuteUnitTests() + registerTransactionUnitTests() + registerExecuteBatchUnitTests() + }) +} + +export function registerTypeORMUnitTests() { + registerTypeORMUnitTestsSpecs() +} diff --git a/example/src/tests/unit/specs/execute.spec.ts b/example/src/tests/unit/specs/execute.spec.ts new file mode 100644 index 00000000..85e1269f --- /dev/null +++ b/example/src/tests/unit/specs/execute.spec.ts @@ -0,0 +1,172 @@ +import { chance, expect, isError, testDb } from '../common' +import { + enableSimpleNullHandling, + NITRO_SQLITE_NULL, +} from 'react-native-nitro-sqlite' +import { describe, it } from '../../MochaRNAdapter' + +export default function registerExecuteUnitTests() { + describe('execute', () => { + describe('Insert', () => { + it('Insert', () => { + const id = chance.integer() + const name = chance.name() + const age = chance.integer() + const networth = chance.floating() + const res = testDb.execute( + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + + expect(res.rowsAffected).to.equal(1) + expect(res.insertId).to.equal(1) + expect(res.rows?._array).to.eql([]) + expect(res.rows?.length).to.equal(0) + expect(res.rows?.item).to.be.a('function') + }) + + it('Insert with null', () => { + const id = chance.integer() + const name = chance.name() + const age = NITRO_SQLITE_NULL + const networth = NITRO_SQLITE_NULL + const res = testDb.execute( + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + + expect(res.rowsAffected).to.equal(1) + expect(res.insertId).to.equal(1) + expect(res.rows?._array).to.eql([]) + expect(res.rows?.length).to.equal(0) + expect(res.rows?.item).to.be.a('function') + + const selectRes = testDb.execute('SELECT * FROM User') + expect(selectRes.rows?._array).to.eql([ + { + id, + name, + age, + networth, + }, + ]) + }) + + it('Insert with null (simple null handling)', () => { + enableSimpleNullHandling(true) + + const id = chance.integer() + const name = chance.name() + const age = undefined + const networth = null + const res = testDb.execute( + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + + expect(res.rowsAffected).to.equal(1) + expect(res.insertId).to.equal(1) + expect(res.rows?._array).to.eql([]) + expect(res.rows?.length).to.equal(0) + expect(res.rows?.item).to.be.a('function') + + const selectRes = testDb.execute('SELECT * FROM User') + expect(selectRes.rows?._array).to.eql([ + { + id, + name, + age: null, + networth: null, + }, + ]) + }) + + it('Failed insert', () => { + const id = chance.integer() + const name = chance.name() + const age = chance.string() + const networth = chance.string() + + try { + testDb.execute( + 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + } catch (e: unknown) { + if (isError(e)) { + expect(e.message).to.include( + 'cannot store TEXT value in REAL column User.age', + ) + } else { + expect.fail('Should have thrown a valid NitroSQLiteException') + } + } + }) + + it('Insertion correctly throws', () => { + const id = chance.string() + const name = chance.name() + const age = chance.integer() + const networth = chance.floating() + try { + testDb.execute( + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + } catch (e: unknown) { + expect(e).to.not.equal(undefined) + } + }) + }) + + describe('Select', () => { + it('Query without params', () => { + const id = chance.integer() + const name = chance.name() + const age = chance.integer() + const networth = chance.floating() + testDb.execute( + 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + + const res = testDb.execute('SELECT * FROM User') + + expect(res.rowsAffected).to.equal(1) + expect(res.insertId).to.equal(1) + expect(res.rows?._array).to.eql([ + { + id, + name, + age, + networth, + }, + ]) + }) + + it('Query with params', () => { + const id = chance.integer() + const name = chance.name() + const age = chance.integer() + const networth = chance.floating() + testDb.execute( + 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ) + + const res = testDb.execute('SELECT * FROM User WHERE id = ?', [id]) + + expect(res.rowsAffected).to.equal(1) + expect(res.insertId).to.equal(1) + expect(res.rows?._array).to.eql([ + { + id, + name, + age, + networth, + }, + ]) + }) + }) + }) +} diff --git a/example/src/tests/unit/specs/executeBatch.spec.ts b/example/src/tests/unit/specs/executeBatch.spec.ts new file mode 100644 index 00000000..f5d776d0 --- /dev/null +++ b/example/src/tests/unit/specs/executeBatch.spec.ts @@ -0,0 +1,80 @@ +import { chance, expect, testDb } from '../common' +import type { BatchQueryCommand } from 'react-native-nitro-sqlite' +import { describe, it } from '../../MochaRNAdapter' + +export default function registerExecuteBatchUnitTests() { + describe('executeBatch', () => { + it('executeBatch', () => { + const id1 = chance.integer() + const name1 = chance.name() + const age1 = chance.integer() + const networth1 = chance.floating() + + const id2 = chance.integer() + const name2 = chance.name() + const age2 = chance.integer() + const networth2 = chance.floating() + const commands: BatchQueryCommand[] = [ + { + query: + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + params: [id1, name1, age1, networth1], + }, + { + query: + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + params: [id2, name2, age2, networth2], + }, + ] + + testDb.executeBatch(commands) + + const res = testDb.execute('SELECT * FROM User') + expect(res.rows?._array).to.eql([ + { id: id1, name: name1, age: age1, networth: networth1 }, + { + id: id2, + name: name2, + age: age2, + networth: networth2, + }, + ]) + }) + + it('Async batch execute', async () => { + const id1 = chance.integer() + const name1 = chance.name() + const age1 = chance.integer() + const networth1 = chance.floating() + const id2 = chance.integer() + const name2 = chance.name() + const age2 = chance.integer() + const networth2 = chance.floating() + const commands: BatchQueryCommand[] = [ + { + query: + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + params: [id1, name1, age1, networth1], + }, + { + query: + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + params: [id2, name2, age2, networth2], + }, + ] + + await testDb.executeBatchAsync(commands) + + const res = testDb.execute('SELECT * FROM User') + expect(res.rows?._array).to.eql([ + { id: id1, name: name1, age: age1, networth: networth1 }, + { + id: id2, + name: name2, + age: age2, + networth: networth2, + }, + ]) + }) + }) +} diff --git a/example/src/tests/unitTests.spec.ts b/example/src/tests/unit/specs/transaction.spec.ts similarity index 60% rename from example/src/tests/unitTests.spec.ts rename to example/src/tests/unit/specs/transaction.spec.ts index 45b4aa07..5c714cdc 100644 --- a/example/src/tests/unitTests.spec.ts +++ b/example/src/tests/unit/specs/transaction.spec.ts @@ -1,189 +1,9 @@ -import Chance from 'chance' -import { - type NitroSQLiteConnection, - type BatchQueryCommand, - NITRO_SQLITE_NULL, - enableSimpleNullHandling, -} from 'react-native-nitro-sqlite' -import { beforeEach, describe, it } from './MochaRNAdapter' -import chai from 'chai' -import { testDb as testDbInternal, resetTestDb } from './db' -import { User } from '../model/User' - -function isError(e: unknown): e is Error { - return e instanceof Error -} - -const expect = chai.expect -const chance = new Chance() - -export function registerUnitTests() { - let testDb: NitroSQLiteConnection - - beforeEach(() => { - enableSimpleNullHandling(false) - - try { - resetTestDb() - - if (testDbInternal == null) - throw new Error('Failed to reset test database') - - testDbInternal.execute('DROP TABLE IF EXISTS User;') - testDbInternal.execute( - 'CREATE TABLE User ( id REAL PRIMARY KEY, name TEXT NOT NULL, age REAL, networth REAL) STRICT;', - ) - - testDb = testDbInternal! - } catch (e) { - console.warn('Error resetting user database', e) - } - }) - - describe('Raw queries', () => { - it('Insert', () => { - const id = chance.integer() - const name = chance.name() - const age = chance.integer() - const networth = chance.floating() - const res = testDb.execute( - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - - expect(res.rowsAffected).to.equal(1) - expect(res.insertId).to.equal(1) - expect(res.rows?._array).to.eql([]) - expect(res.rows?.length).to.equal(0) - expect(res.rows?.item).to.be.a('function') - }) - - it('Insert with null', () => { - const id = chance.integer() - const name = chance.name() - const age = NITRO_SQLITE_NULL - const networth = NITRO_SQLITE_NULL - const res = testDb.execute( - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - - expect(res.rowsAffected).to.equal(1) - expect(res.insertId).to.equal(1) - expect(res.rows?._array).to.eql([]) - expect(res.rows?.length).to.equal(0) - expect(res.rows?.item).to.be.a('function') - - const selectRes = testDb.execute('SELECT * FROM User') - expect(selectRes.rows?._array).to.eql([ - { - id, - name, - age, - networth, - }, - ]) - }) - - it('Insert with null (simple null handling)', () => { - enableSimpleNullHandling(true) - - const id = chance.integer() - const name = chance.name() - const age = undefined - const networth = null - const res = testDb.execute( - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - - expect(res.rowsAffected).to.equal(1) - expect(res.insertId).to.equal(1) - expect(res.rows?._array).to.eql([]) - expect(res.rows?.length).to.equal(0) - expect(res.rows?.item).to.be.a('function') - - const selectRes = testDb.execute('SELECT * FROM User') - expect(selectRes.rows?._array).to.eql([ - { - id, - name, - age: null, - networth: null, - }, - ]) - }) - - it('Query without params', () => { - const id = chance.integer() - const name = chance.name() - const age = chance.integer() - const networth = chance.floating() - testDb.execute( - 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - - const res = testDb.execute('SELECT * FROM User') - - expect(res.rowsAffected).to.equal(1) - expect(res.insertId).to.equal(1) - expect(res.rows?._array).to.eql([ - { - id, - name, - age, - networth, - }, - ]) - }) - - it('Query with params', () => { - const id = chance.integer() - const name = chance.name() - const age = chance.integer() - const networth = chance.floating() - testDb.execute( - 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - - const res = testDb.execute('SELECT * FROM User WHERE id = ?', [id]) - - expect(res.rowsAffected).to.equal(1) - expect(res.insertId).to.equal(1) - expect(res.rows?._array).to.eql([ - { - id, - name, - age, - networth, - }, - ]) - }) - - it('Failed insert', () => { - const id = chance.integer() - const name = chance.name() - const age = chance.string() - const networth = chance.string() - - try { - testDb.execute( - 'INSERT INTO User (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - } catch (e: unknown) { - if (isError(e)) { - expect(e.message).to.include( - 'cannot store TEXT value in REAL column User.age', - ) - } else { - expect.fail('Should have thrown a valid NitroSQLiteException') - } - } - }) +import { chance, expect, isError, testDb } from '../common' +import { describe, it } from '../../MochaRNAdapter' +import type { User } from '../../../model/User' +export default function registerTransactionUnitTests() { + describe('transaction', () => { it('Transaction, auto commit', async () => { const id = chance.integer() const name = chance.name() @@ -263,14 +83,14 @@ export function registerUnitTests() { // ACT: Upsert statement to create record / increment the value tx.execute( ` - INSERT OR REPLACE INTO [User] ([id], [name], [age], [networth]) - SELECT ?, ?, ?, - IFNULL(( - SELECT [networth] + 1000 - FROM [User] - WHERE [id] = ? - ), 0) - `, + INSERT OR REPLACE INTO [User] ([id], [name], [age], [networth]) + SELECT ?, ?, ?, + IFNULL(( + SELECT [networth] + 1000 + FROM [User] + WHERE [id] = ? + ), 0) + `, [id, name, age, id], ) @@ -359,21 +179,6 @@ export function registerUnitTests() { expect(res.rows?._array).to.eql([]) }) - it('Correctly throws', () => { - const id = chance.string() - const name = chance.name() - const age = chance.integer() - const networth = chance.floating() - try { - testDb.execute( - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - [id, name, age, networth], - ) - } catch (e: unknown) { - expect(e).to.not.equal(undefined) - } - }) - it('Rollback', async () => { const id = chance.integer() const name = chance.name() @@ -556,14 +361,14 @@ export function registerUnitTests() { // ACT: Upsert statement to create record / increment the value await tx.executeAsync( ` - INSERT OR REPLACE INTO [User] ([id], [name], [age], [networth]) - SELECT ?, ?, ?, - IFNULL(( - SELECT [networth] + 1000 - FROM [User] - WHERE [id] = ? - ), 0) - `, + INSERT OR REPLACE INTO [User] ([id], [name], [age], [networth]) + SELECT ?, ?, ?, + IFNULL(( + SELECT [networth] + 1000 + FROM [User] + WHERE [id] = ? + ), 0) + `, [id, name, age, id], ) @@ -625,78 +430,5 @@ export function registerUnitTests() { else expect.fail('Should have thrown a valid NitroSQLiteException') } }) - - it('Batch execute', () => { - const id1 = chance.integer() - const name1 = chance.name() - const age1 = chance.integer() - const networth1 = chance.floating() - - const id2 = chance.integer() - const name2 = chance.name() - const age2 = chance.integer() - const networth2 = chance.floating() - const commands: BatchQueryCommand[] = [ - { - query: - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - params: [id1, name1, age1, networth1], - }, - { - query: - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - params: [id2, name2, age2, networth2], - }, - ] - - testDb.executeBatch(commands) - - const res = testDb.execute('SELECT * FROM User') - expect(res.rows?._array).to.eql([ - { id: id1, name: name1, age: age1, networth: networth1 }, - { - id: id2, - name: name2, - age: age2, - networth: networth2, - }, - ]) - }) - - it('Async batch execute', async () => { - const id1 = chance.integer() - const name1 = chance.name() - const age1 = chance.integer() - const networth1 = chance.floating() - const id2 = chance.integer() - const name2 = chance.name() - const age2 = chance.integer() - const networth2 = chance.floating() - const commands: BatchQueryCommand[] = [ - { - query: - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - params: [id1, name1, age1, networth1], - }, - { - query: - 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', - params: [id2, name2, age2, networth2], - }, - ] - - await testDb.executeBatchAsync(commands) - - const res = testDb.execute('SELECT * FROM User') - expect(res.rows?._array).to.eql([ - { id: id1, name: name1, age: age1, networth: networth1 }, - { - id: id2, - name: name2, - age: age2, - networth: networth2, - }, - ]) - }) }) } diff --git a/example/src/tests/typeorm.spec.ts b/example/src/tests/unit/specs/typeorm.spec.ts similarity index 80% rename from example/src/tests/typeorm.spec.ts rename to example/src/tests/unit/specs/typeorm.spec.ts index 5e51eecb..3ee5f724 100644 --- a/example/src/tests/typeorm.spec.ts +++ b/example/src/tests/unit/specs/typeorm.spec.ts @@ -1,18 +1,16 @@ +import { expect } from '../common' +import { beforeAll, beforeEachAsync, describe, it } from '../../MochaRNAdapter' import type { Repository } from 'typeorm' import { DataSource } from 'typeorm' -import { beforeAll, it, describe, beforeEachAsync } from './MochaRNAdapter' import { typeORMDriver } from 'react-native-nitro-sqlite' -import { User } from '../model/User' -import { Book } from '../model/Book' -import chai from 'chai' - -const expect = chai.expect +import { User } from '../../../model/User' +import { Book } from '../../../model/Book' let dataSource: DataSource let userRepository: Repository let bookRepository: Repository -export function registerTypeORMTests() { +export default function registerTypeORMUnitTests() { describe('Typeorm tests', () => { beforeAll((done) => { dataSource = new DataSource({