Skip to content

Commit 9f68031

Browse files
author
Gery Hirschfeld
authored
Merge pull request #54 from w3tecch/feat/testing
Feat/testing
2 parents aadf783 + f3b0f2d commit 9f68031

15 files changed

+279
-141
lines changed

README.md

+110-30
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@
3030
- [Introduction](#-introduction)
3131
- [Installation](#-installation)
3232
- [Basic Seeder](#-basic-seeder)
33-
- [Factory API](#-factory-api)
33+
- [Using Entity Factory](#-using-entity-factory)
34+
- [Seeding Data in Testing](#-seeding-data-in-testing)
3435
- [Changelog](#-changelog)
3536
- [License](#-license)
3637

3738
## ❯ Introduction
3839

3940
Isn't it exhausting to create some sample data for your database, well this time is over!
4041

41-
How does it work? Just create a factory for your entities (models) and a seed script.
42+
How does it work? Just create a entity factory for your entities (models) and a seed script.
4243

4344
### Enity
4445

@@ -74,9 +75,9 @@ export class Pet {
7475

7576
### Factory
7677

77-
The purpose of a factory is to create new fake entites with generate data.
78+
Then for each entity define a factory. The purpose of a factory is to create new entites with generate data.
7879

79-
> Factories can also be used to generate test data for some unit, integration or e2e tests.
80+
> Note: Factories can also be used to generate data for testing.
8081
8182
```typescript
8283
// user.factory.ts
@@ -106,13 +107,16 @@ define(Pet, (faker: typeof Faker) => {
106107

107108
### Seeder
108109

109-
The seeder can be called by the configured cli command `seed:run`. In this case it generates 10 pets with a owner (User).
110+
111+
And last but not least, create a seeder. The seeder can be called by the configured cli command `seed:run`. In this case it generates 10 pets with a owner (User).
112+
113+
> Note: `seed:run` must be configured first. Go to [CLI Configuration](#cli-configuration).
110114
111115
```typescript
112116
// create-pets.seed.ts
113117
export default class CreatePets implements Seeder {
114118
public async run(factory: Factory, connection: Connection): Promise<any> {
115-
await factory(Pet)().seedMany(10)
119+
await factory(Pet)().createMany(10)
116120
}
117121
}
118122
```
@@ -121,15 +125,15 @@ export default class CreatePets implements Seeder {
121125

122126
Before using this TypeORM extension please read the [TypeORM Getting Started](https://typeorm.io/#/) documentation. This explains how to setup a TypeORM project.
123127

124-
You can install our extension with `npm` or `yarn`.
128+
After that install the extension with `npm` or `yarn`.
125129

126130
```bash
127131
npm i typeorm-seeding
128132
# or
129133
yarn add typeorm-seeding
130134
```
131135

132-
Optional, for `Faker` types
136+
Optional, install the type definitions of the `Faker` library.
133137

134138
```bash
135139
npm install -D @types/faker
@@ -139,7 +143,7 @@ npm install -D @types/faker
139143

140144
To configure the path to your seeds and factories change the TypeORM config file(ormconfig.js or ormconfig.json).
141145

142-
> Default is `src/database/{seeds,factories}/**/*{.ts,.js}`
146+
> The default paths are `src/database/{seeds,factories}/**/*{.ts,.js}`
143147
144148
**ormconfig.js**
145149

@@ -160,7 +164,7 @@ TYPEORM_SEEDING_SEEDS=src/seeds/**/*{.ts,.js}
160164

161165
### CLI Configuration
162166

163-
Add the following scripts to your `package.json` file.
167+
Add the following scripts to your `package.json` file to configure the seed cli commands.
164168

165169
```
166170
"scripts": {
@@ -170,7 +174,9 @@ Add the following scripts to your `package.json` file.
170174
}
171175
```
172176

173-
> Now you are able to execute your seeds with this command `npm run seed:run`.
177+
To execute the seed run `npm run seed:run` in the terminal.
178+
179+
> Note: More CLI optios are [here](#cli-options)
174180
175181
Add the following TypeORM cli commands to the package.json to drop and sync the database.
176182

@@ -187,14 +193,16 @@ Add the following TypeORM cli commands to the package.json to drop and sync the
187193

188194
| Option | Default | Description |
189195
| ---------------------- | --------------- | --------------------------------------------------------------------------- |
190-
| `--seed` or `-s` | null | Option to specify a specific seeder class to run individually. |
196+
| `--seed` or `-s` | null | Option to specify a seeder class to run individually. |
191197
| `--connection` or `-c` | null | Name of the typeorm connection. Required if there are multiple connections. |
192198
| `--configName` or `-n` | `ormconfig.js` | Name to the typeorm config file. |
193199
| `--root` or `-r` | `process.cwd()` | Path to the typeorm config file. |
194200

195201
## ❯ Basic Seeder
196202

197-
The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.
203+
A seeder class only contains one method by default `run`. Within this method, you may insert data into your database. For manually insertion use the [Query Builder](https://typeorm.io/#/select-query-builder) or use the [Entity Factory](#-using-entity-factory)
204+
205+
> Note. The seeder files will be executed alphabetically.
198206
199207
```typescript
200208
import { Factory, Seeder } from 'typeorm-seeding'
@@ -216,15 +224,17 @@ export default class CreateUsers implements Seeder {
216224
}
217225
```
218226

219-
## ❯ Factory API
227+
## ❯ Using Entity Factory
228+
229+
Of course, manually specifying the attributes for each entity seed is cumbersome. Instead, you can use entity factories to conveniently generate large amounts of database records.
220230

221-
For all entities we want to seed, we need to define a factory. To do so we give you the awesome [faker](https://github.com/marak/Faker.js/) library as a parameter into your factory. Then create your "fake" entity and return it. Those factory files should be in the `src/database/factories` folder and suffixed with `.factory` like `src/database/factories/user.factory.ts`.
231+
For all entities we want to create, we need to define a factory. To do so we give you the awesome [faker](https://github.com/marak/Faker.js/) library as a parameter into your factory. Then create your "fake" entity and return it. Those factory files should be in the `src/database/factories` folder and suffixed with `.factory` like `src/database/factories/user.factory.ts`.
222232

223-
| Types | Description |
224-
| --------------- | ----------------------------------------------------------------------------- |
225-
| `Enity` | TypeORM Enity like the user or the pet in the samples. |
226-
| `Context` | Argument to pass some static data into the factory function. |
227-
| `EntityFactory` | This object is used to make new filled entities or seed it into the database. |
233+
| Types | Description |
234+
| --------------- | ------------------------------------------------------------------------------- |
235+
| `Enity` | TypeORM Enity like the user or the pet in the samples. |
236+
| `Context` | Argument to pass some static data into the factory function. |
237+
| `EntityFactory` | This object is used to make new filled entities or create it into the database. |
228238

229239
### `define`
230240

@@ -268,16 +278,16 @@ map(mapFunction: (entity: Entity) => Promise<Entity>): EntityFactory<Entity, Con
268278
```typescript
269279
await factory(User)()
270280
.map(async (user: User) => {
271-
const pets: Pet[] = await factory(Pet)().seedMany(2)
281+
const pets: Pet[] = await factory(Pet)().createMany(2)
272282
const petIds = pets.map((pet: Pet) => pet.Id)
273283
await user.pets().attach(petIds)
274284
})
275-
.seedMany(5)
285+
.createMany(5)
276286
```
277287

278288
#### `make` & `makeMany`
279289

280-
Make and makeMany executes the factory functions and return a new instance of the given enity. The instance is filled with the generated values from the factory function.
290+
Make and makeMany executes the factory functions and return a new instance of the given enity. The instance is filled with the generated values from the factory function, but not saved in the database.
281291

282292
**overrideParams** - Override some of the attributes of the enity.
283293

@@ -294,23 +304,93 @@ await factory(User)().make({ email: '[email protected]' })
294304
await factory(User)().makeMany(10, { email: '[email protected]' })
295305
```
296306

297-
#### `seed` & `seedMany`
307+
#### `create` & `createMany`
298308

299-
seed and seedMany is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database.
309+
the create and createMany method is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database.
300310

301311
**overrideParams** - Override some of the attributes of the enity.
302312

303313
```typescript
304-
seed(overrideParams: EntityProperty<Entity> = {}): Promise<Entity>
314+
create(overrideParams: EntityProperty<Entity> = {}): Promise<Entity>
305315
```
306316

307317
```typescript
308-
await factory(User)().seed()
309-
await factory(User)().seedMany(10)
318+
await factory(User)().create()
319+
await factory(User)().createMany(10)
310320

311321
// override the email
312-
await factory(User)().seed({ email: '[email protected]' })
313-
await factory(User)().seedMany(10, { email: '[email protected]' })
322+
await factory(User)().create({ email: '[email protected]' })
323+
await factory(User)().createMany(10, { email: '[email protected]' })
324+
```
325+
326+
## ❯ Seeding Data in Testing
327+
328+
The entity factories can also be used in testing. To do so call the `useSeeding` function, which loads all the defined entity factories.
329+
330+
> Note: Normally Jest parallelizes test runs, which all conect to the same database. This could lead to strange sideeffects. So use the `--runInBand` flag to disable parallelizes runs.
331+
332+
```typescript
333+
describe("UserService", () => {
334+
beforeAll(async (done) => {
335+
await useRefreshDatabase()
336+
await useSeeding()
337+
338+
const user = await factory(User)().make()
339+
const createdUser = await factory(User)().create()
340+
341+
await runSeeder(CreateUserSeed)
342+
done()
343+
})
344+
345+
afterAll(async (done) => {
346+
await tearDownDatabase()
347+
done()
348+
})
349+
350+
test('Should ...', () => { ... })
351+
})
352+
```
353+
354+
### `useSeeding`
355+
356+
Loads the defined entity factories.
357+
358+
```typescript
359+
useSeeding(options: ConfigureOption = {}): Promise<void>
360+
```
361+
362+
### `runSeeder`
363+
364+
Runs the given seeder class.
365+
366+
```typescript
367+
useSeeding(seed: SeederConstructor): Promise<void>
368+
```
369+
370+
### `useRefreshDatabase`
371+
372+
Connects to the database, drops it and recreates the schema.
373+
374+
```typescript
375+
useRefreshDatabase(options: ConfigureOption = {}): Promise<Connection>
376+
```
377+
378+
### `tearDownDatabase`
379+
380+
Closes the open database connection.
381+
382+
```typescript
383+
tearDownDatabase(): Promise<void>
384+
```
385+
386+
### `ConfigureOption`
387+
388+
```typescript
389+
interface ConfigureOption {
390+
root?: string // path to the orm config file. Default = process.cwd()
391+
configName?: string // name of the config file. eg. ormconfig.js
392+
connection?: string // name of the database connection.
393+
}
314394
```
315395

316396
## ❯ Changelog

jest.config.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
};

logo.png

2.62 KB
Loading

ormconfig.js

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const path = require('path')
2-
31
module.exports = [
42
{
53
name: 'sample',

package.json

+2-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typeorm-seeding",
3-
"version": "1.4.3",
3+
"version": "1.4.4",
44
"description": "🌱 A delightful way to seed test data into your database.",
55
"license": "MIT",
66
"author": "Gery Hirschfeld <[email protected]> (https://github.com/hirsch88)",
@@ -17,7 +17,7 @@
1717
"prebuild": "rimraf dist",
1818
"format": "prettier --write \"src/**/*.ts\"",
1919
"lint": "eslint \"src/**/*.ts\" --fix",
20-
"build": "tsc --project ./tsconfig.build.json",
20+
"build": "npm run prebuild && tsc --project ./tsconfig.build.json",
2121
"watch": "rollup -cw",
2222
"test": "jest",
2323
"test:watch": "jest --watch",
@@ -67,19 +67,5 @@
6767
},
6868
"resolutions": {
6969
"mem": ">=4.0.0"
70-
},
71-
"jest": {
72-
"moduleFileExtensions": [
73-
"js",
74-
"json",
75-
"ts"
76-
],
77-
"rootDir": "src",
78-
"testRegex": ".test.ts$",
79-
"transform": {
80-
"^.+\\.(t|j)s$": "ts-jest"
81-
},
82-
"coverageDirectory": "../coverage",
83-
"testEnvironment": "node"
8470
}
8571
}

sample/seeds/create-pets.seed.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { Pet } from '../entities/Pet.entity'
44

55
export default class CreatePets implements Seeder {
66
public async run(factory: Factory, connection: Connection): Promise<any> {
7-
await factory(Pet)().seed()
7+
await factory(Pet)().create()
88
}
99
}

sample/seeds/create-users.seed.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import { User } from '../entities/User.entity'
33

44
export default class CreateUsers implements Seeder {
55
public async run(factory: Factory): Promise<void> {
6-
await factory(User)({ roles: [] }).seedMany(10)
6+
await factory(User)({ roles: [] }).createMany(10)
77
}
88
}

src/commands/config.command.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as yargs from 'yargs'
22
import * as chalk from 'chalk'
3-
import { getConnectionOption } from '../typeorm-seeding'
43
import { printError } from '../utils/log.util'
4+
import { configureConnection, getConnectionOptions } from '../connection'
55

66
export class ConfigCommand implements yargs.CommandModule {
77
command = 'config'
@@ -29,15 +29,14 @@ export class ConfigCommand implements yargs.CommandModule {
2929
async handler(args: yargs.Arguments) {
3030
const log = console.log
3131
const pkg = require('../../package.json')
32-
log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`))
32+
log('🌱 ' + chalk.bold(`TypeORM Seeding v${(pkg as any).version}`))
3333
try {
34-
const option = await getConnectionOption(
35-
{
36-
root: args.root as string,
37-
configName: args.configName as string,
38-
},
39-
args.connection as string,
40-
)
34+
configureConnection({
35+
root: args.root as string,
36+
configName: args.configName as string,
37+
connection: args.connection as string,
38+
})
39+
const option = await getConnectionOptions()
4140
log(option)
4241
} catch (error) {
4342
printError('Could not find the orm config file', error)

0 commit comments

Comments
 (0)