@geekmidas/testkit 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -513,28 +513,113 @@ describe('User Service', () => {
513
513
 
514
514
  ## Seeds
515
515
 
516
- Seeds are functions that create complex test scenarios:
516
+ Seeds are functions that create complex test scenarios. Use `createSeed` to define type-safe seed functions that receive `{ attrs, factory, db }` as a single context object:
517
+
518
+ ### Defining Seeds with Kysely
517
519
 
518
520
  ```typescript
519
- const blogSeed = async (factory: Factory) => {
520
- const author = await factory.insert('user', {
521
- name: 'Blog Author',
522
- role: 'author',
523
- });
521
+ import { KyselyFactory } from '@geekmidas/testkit/kysely';
522
+
523
+ // Define seeds using createSeed for type safety
524
+ const seeds = {
525
+ // Simple seed with typed attrs
526
+ adminUser: KyselyFactory.createSeed(
527
+ async ({ attrs, factory }: {
528
+ attrs: { name?: string };
529
+ factory: KyselyFactory<Database, typeof builders, {}>;
530
+ db: Kysely<Database>
531
+ }) => {
532
+ return factory.insert('user', {
533
+ name: attrs.name || 'Admin User',
534
+ role: 'admin',
535
+ });
536
+ }
537
+ ),
538
+
539
+ // Complex seed creating related records
540
+ blogWithPosts: KyselyFactory.createSeed(
541
+ async ({ attrs, factory }) => {
542
+ const author = await factory.insert('user', {
543
+ name: attrs.authorName || 'Blog Author',
544
+ role: 'author',
545
+ });
524
546
 
525
- const categories = await factory.insertMany(3, 'category');
547
+ const categories = await factory.insertMany(3, 'category');
526
548
 
527
- const posts = await factory.insertMany(5, 'post', (index) => ({
528
- title: `Post ${index + 1}`,
529
- authorId: author.id,
530
- categoryId: categories[index % categories.length].id,
531
- }));
549
+ const posts = await factory.insertMany(attrs.postCount || 5, 'post', (index) => ({
550
+ title: `Post ${index + 1}`,
551
+ authorId: author.id,
552
+ categoryId: categories[index % categories.length].id,
553
+ }));
532
554
 
533
- return { author, categories, posts };
555
+ return { author, categories, posts };
556
+ }
557
+ ),
534
558
  };
535
559
 
536
- // Use in tests
537
- const data = await factory.seed('blog');
560
+ // Create factory with seeds
561
+ const factory = new KyselyFactory(builders, seeds, db);
562
+
563
+ // Use in tests - attrs are type-safe
564
+ const admin = await factory.seed('adminUser', { name: 'Super Admin' });
565
+ const blog = await factory.seed('blogWithPosts', {
566
+ authorName: 'Jane Doe',
567
+ postCount: 10
568
+ });
569
+ ```
570
+
571
+ ### Defining Seeds with Objection.js
572
+
573
+ ```typescript
574
+ import { ObjectionFactory } from '@geekmidas/testkit/objection';
575
+ import type { Knex } from 'knex';
576
+
577
+ const seeds = {
578
+ userWithProfile: ObjectionFactory.createSeed(
579
+ async ({ attrs, factory, db }: {
580
+ attrs: { email?: string };
581
+ factory: ObjectionFactory<typeof builders, {}>;
582
+ db: Knex
583
+ }) => {
584
+ const user = await factory.insert('user', {
585
+ email: attrs.email || 'user@example.com',
586
+ });
587
+
588
+ await factory.insert('profile', { userId: user.id });
589
+
590
+ return user;
591
+ }
592
+ ),
593
+ };
594
+
595
+ const factory = new ObjectionFactory(builders, seeds, knex);
596
+ const user = await factory.seed('userWithProfile', { email: 'custom@example.com' });
597
+ ```
598
+
599
+ ### Seed Context Object
600
+
601
+ All seed functions receive a single context object with three properties:
602
+
603
+ | Property | Description |
604
+ |----------|-------------|
605
+ | `attrs` | Configuration attributes passed to `factory.seed()` |
606
+ | `factory` | The factory instance for creating records |
607
+ | `db` | The database connection (Kysely or Knex transaction) |
608
+
609
+ This pattern allows you to destructure only what you need:
610
+
611
+ ```typescript
612
+ // Use all three
613
+ KyselyFactory.createSeed(async ({ attrs, factory, db }) => {
614
+ // Direct db access for complex queries
615
+ const existing = await db.selectFrom('users').where('role', '=', 'admin').execute();
616
+ // ...
617
+ });
618
+
619
+ // Or just what you need
620
+ KyselyFactory.createSeed(async ({ factory }) => {
621
+ return factory.insert('user');
622
+ });
538
623
  ```
539
624
 
540
625
  ## API Reference
@@ -549,6 +634,7 @@ class KyselyFactory<DB, Builders, Seeds> {
549
634
  db: Kysely<DB> | ControlledTransaction<DB>
550
635
  );
551
636
 
637
+ // Create a type-safe builder for a specific table
552
638
  static createBuilder<DB, TableName extends keyof DB & string>(
553
639
  table: TableName,
554
640
  defaults?: (context: {
@@ -560,20 +646,28 @@ class KyselyFactory<DB, Builders, Seeds> {
560
646
  autoInsert?: boolean
561
647
  ): BuilderFunction;
562
648
 
649
+ // Create a type-safe seed function
650
+ static createSeed<Seed extends FactorySeed>(
651
+ seedFn: (context: { attrs: Attrs; factory: Factory; db: DB }) => Promise<Result>
652
+ ): Seed;
653
+
654
+ // Insert a single record
563
655
  insert<K extends keyof Builders>(
564
656
  builderName: K,
565
657
  attrs?: Partial<BuilderAttrs>
566
658
  ): Promise<BuilderResult>;
567
659
 
660
+ // Insert multiple records
568
661
  insertMany<K extends keyof Builders>(
569
662
  count: number,
570
663
  builderName: K,
571
664
  attrs?: Partial<BuilderAttrs> | ((idx: number, faker: FakerFactory) => Partial<BuilderAttrs>)
572
665
  ): Promise<BuilderResult[]>;
573
666
 
667
+ // Execute a seed function
574
668
  seed<K extends keyof Seeds>(
575
669
  seedName: K,
576
- attrs?: SeedAttrs
670
+ attrs?: ExtractSeedAttrs<Seeds[K]> // Attrs type is extracted from seed function
577
671
  ): Promise<SeedResult>;
578
672
  }
579
673
  ```
@@ -1,4 +1,4 @@
1
- import { FakerFactory } from "./faker-CbYiF-8_.cjs";
1
+ import { FakerFactory } from "./faker-Cg76aFNO.cjs";
2
2
 
3
3
  //#region src/Factory.d.ts
4
4
 
@@ -143,4 +143,4 @@ type ExtractSeedAttrs<T> = T extends ((context: {
143
143
  }) => any) ? A : never;
144
144
  //#endregion
145
145
  export { ExtractSeedAttrs, Factory, FactorySeed, MixedFactoryBuilder };
146
- //# sourceMappingURL=Factory-IdfEkOeT.d.cts.map
146
+ //# sourceMappingURL=Factory-BK06XuDA.d.cts.map
@@ -1,3 +1,3 @@
1
- import "./faker-CbYiF-8_.cjs";
2
- import { ExtractSeedAttrs, Factory, FactorySeed, MixedFactoryBuilder } from "./Factory-IdfEkOeT.cjs";
1
+ import "./faker-Cg76aFNO.cjs";
2
+ import { ExtractSeedAttrs, Factory, FactorySeed, MixedFactoryBuilder } from "./Factory-BK06XuDA.cjs";
3
3
  export { ExtractSeedAttrs, Factory, FactorySeed, MixedFactoryBuilder };
@@ -1,5 +1,5 @@
1
- import { FakerFactory } from "./faker-CbYiF-8_.cjs";
2
- import { ExtractSeedAttrs, Factory, FactorySeed } from "./Factory-IdfEkOeT.cjs";
1
+ import { FakerFactory } from "./faker-Cg76aFNO.cjs";
2
+ import { ExtractSeedAttrs, Factory, FactorySeed } from "./Factory-BK06XuDA.cjs";
3
3
  import { ControlledTransaction, Insertable, Kysely, Selectable } from "kysely";
4
4
 
5
5
  //#region src/KyselyFactory.d.ts
@@ -224,4 +224,4 @@ declare class KyselyFactory<DB, Builders extends Record<string, any>, Seeds exte
224
224
  }
225
225
  //#endregion
226
226
  export { KyselyFactory };
227
- //# sourceMappingURL=KyselyFactory-Dxhi_ZkA.d.cts.map
227
+ //# sourceMappingURL=KyselyFactory-Bu9ssWZP.d.cts.map
@@ -1,4 +1,4 @@
1
- import "./faker-CbYiF-8_.cjs";
2
- import "./Factory-IdfEkOeT.cjs";
3
- import { KyselyFactory } from "./KyselyFactory-Dxhi_ZkA.cjs";
1
+ import "./faker-Cg76aFNO.cjs";
2
+ import "./Factory-BK06XuDA.cjs";
3
+ import { KyselyFactory } from "./KyselyFactory-Bu9ssWZP.cjs";
4
4
  export { KyselyFactory };
@@ -1,5 +1,5 @@
1
- import { FakerFactory } from "./faker-CbYiF-8_.cjs";
2
- import { ExtractSeedAttrs, Factory, FactorySeed } from "./Factory-IdfEkOeT.cjs";
1
+ import { FakerFactory } from "./faker-Cg76aFNO.cjs";
2
+ import { ExtractSeedAttrs, Factory, FactorySeed } from "./Factory-BK06XuDA.cjs";
3
3
  import { Knex } from "knex";
4
4
  import { Model } from "objection";
5
5
 
@@ -237,4 +237,4 @@ declare class ObjectionFactory<Builders extends Record<string, any>, Seeds exten
237
237
  }
238
238
  //#endregion
239
239
  export { ObjectionFactory };
240
- //# sourceMappingURL=ObjectionFactory-BRAkAByP.d.cts.map
240
+ //# sourceMappingURL=ObjectionFactory-tKWZOiYO.d.cts.map
@@ -1,4 +1,4 @@
1
- import "./faker-CbYiF-8_.cjs";
2
- import "./Factory-IdfEkOeT.cjs";
3
- import { ObjectionFactory } from "./ObjectionFactory-BRAkAByP.cjs";
1
+ import "./faker-Cg76aFNO.cjs";
2
+ import "./Factory-BK06XuDA.cjs";
3
+ import { ObjectionFactory } from "./ObjectionFactory-tKWZOiYO.cjs";
4
4
  export { ObjectionFactory };
@@ -9,4 +9,4 @@ interface DirectoryFixtures {
9
9
  }
10
10
  //#endregion
11
11
  export { DirectoryFixtures, itWithDir };
12
- //# sourceMappingURL=directory-Mi7tdOuD.d.cts.map
12
+ //# sourceMappingURL=directory-BPf1LgNX.d.mts.map
@@ -9,4 +9,4 @@ interface DirectoryFixtures {
9
9
  }
10
10
  //#endregion
11
11
  export { DirectoryFixtures, itWithDir };
12
- //# sourceMappingURL=directory-BXavAeJZ.d.mts.map
12
+ //# sourceMappingURL=directory-DlkPEzL4.d.cts.map
@@ -1,4 +1,4 @@
1
- import * as _faker_js_faker3 from "@faker-js/faker";
1
+ import * as _faker_js_faker1 from "@faker-js/faker";
2
2
 
3
3
  //#region src/faker.d.ts
4
4
 
@@ -134,7 +134,7 @@ declare function coordinateOutsideRadius(center: Coordinate, minRadiusMeters: nu
134
134
  * const productPrice = faker.price();
135
135
  * ```
136
136
  */
137
- declare const faker: Readonly<_faker_js_faker3.Faker & {
137
+ declare const faker: Readonly<_faker_js_faker1.Faker & {
138
138
  timestamps: typeof timestamps;
139
139
  identifier: typeof identifier;
140
140
  sequence: typeof sequence;
@@ -163,4 +163,4 @@ type Timestamps = {
163
163
  type FakerFactory = typeof faker;
164
164
  //#endregion
165
165
  export { FakerFactory, Timestamps, coordinateInRadius, faker, identifier, resetAllSequences, resetSequence, sequence, timestamps };
166
- //# sourceMappingURL=faker-CbYiF-8_.d.cts.map
166
+ //# sourceMappingURL=faker-Cg76aFNO.d.cts.map
package/dist/faker.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { FakerFactory, Timestamps, coordinateInRadius, faker, identifier, resetAllSequences, resetSequence, sequence, timestamps } from "./faker-CbYiF-8_.cjs";
1
+ import { FakerFactory, Timestamps, coordinateInRadius, faker, identifier, resetAllSequences, resetSequence, sequence, timestamps } from "./faker-Cg76aFNO.cjs";
2
2
  export { FakerFactory, Timestamps, coordinateInRadius, faker, identifier, resetAllSequences, resetSequence, sequence, timestamps };
package/dist/kysely.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { FakerFactory, faker } from "./faker-CbYiF-8_.cjs";
2
- import { ExtractSeedAttrs, FactorySeed } from "./Factory-IdfEkOeT.cjs";
3
- import { KyselyFactory } from "./KyselyFactory-Dxhi_ZkA.cjs";
1
+ import { FakerFactory, faker } from "./faker-Cg76aFNO.cjs";
2
+ import { ExtractSeedAttrs, FactorySeed } from "./Factory-BK06XuDA.cjs";
3
+ import { KyselyFactory } from "./KyselyFactory-Bu9ssWZP.cjs";
4
4
  import "./PostgresMigrator-D5UkK1_K.cjs";
5
5
  import { PostgresKyselyMigrator } from "./PostgresKyselyMigrator-CQ3aUoy_.cjs";
6
6
  import { DatabaseConnection, DatabaseFixtures, ExtendedDatabaseFixtures, FixtureCreators, IsolationLevel, TestWithExtendedFixtures, TransactionWrapperOptions } from "./VitestTransactionIsolator-CwQaxZLP.cjs";
@@ -1,6 +1,6 @@
1
- import { FakerFactory, faker } from "./faker-CbYiF-8_.cjs";
2
- import { ExtractSeedAttrs, FactorySeed } from "./Factory-IdfEkOeT.cjs";
3
- import { ObjectionFactory } from "./ObjectionFactory-BRAkAByP.cjs";
1
+ import { FakerFactory, faker } from "./faker-Cg76aFNO.cjs";
2
+ import { ExtractSeedAttrs, FactorySeed } from "./Factory-BK06XuDA.cjs";
3
+ import { ObjectionFactory } from "./ObjectionFactory-tKWZOiYO.cjs";
4
4
  import "./PostgresMigrator-D5UkK1_K.cjs";
5
5
  import { PostgresObjectionMigrator } from "./PostgresObjectionMigrator-CZHHcCOv.cjs";
6
6
  import { DatabaseConnection, DatabaseFixtures, ExtendedDatabaseFixtures, FixtureCreators, IsolationLevel, TestWithExtendedFixtures, TransactionWrapperOptions } from "./VitestTransactionIsolator-CwQaxZLP.cjs";
@@ -1,2 +1,2 @@
1
- import { DirectoryFixtures, itWithDir } from "../directory-Mi7tdOuD.cjs";
1
+ import { DirectoryFixtures, itWithDir } from "../directory-DlkPEzL4.cjs";
2
2
  export { DirectoryFixtures, itWithDir };
@@ -1,2 +1,2 @@
1
- import { DirectoryFixtures, itWithDir } from "../directory-BXavAeJZ.mjs";
1
+ import { DirectoryFixtures, itWithDir } from "../directory-BPf1LgNX.mjs";
2
2
  export { DirectoryFixtures, itWithDir };
@@ -1,2 +1,2 @@
1
- import { itWithDir } from "../directory-Mi7tdOuD.cjs";
1
+ import { itWithDir } from "../directory-DlkPEzL4.cjs";
2
2
  export { itWithDir };
@@ -1,2 +1,2 @@
1
- import { itWithDir } from "../directory-BXavAeJZ.mjs";
1
+ import { itWithDir } from "../directory-BPf1LgNX.mjs";
2
2
  export { itWithDir };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/testkit",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {