Skip to content

Commit

Permalink
Cleaned up guide, added nested fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
Noah Bogart committed Jul 9, 2020
1 parent b37e084 commit 4d531cf
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 80 deletions.
119 changes: 81 additions & 38 deletions docs/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ expect(user.email).to.equal("test1@example.com");
As seen above, each fixture has a name, a model class, and a function for defining the
attributes.

```javascript
fr.fixture("post", Post, (f) => {
f.attr("title", () => "First post!");
f.attr("body", () => "Thank you for reading.");
});
```

### Explicit vs Implicit attributes
When defining attributes, you can use the explicit function `attr`, which takes the
attribute name as the first argument:
Expand Down Expand Up @@ -96,7 +89,7 @@ fr.fixture("user", User, (f) => {
f.lastName(() => "Bogart");
});

const user = await fr.create("user");
const user = await fr.build("user");
user.email === "noah-bogart@example.com";
// > true
```
Expand All @@ -121,32 +114,6 @@ fr.fixture("user", User, function() {
});
```

## Using fixtures
A defined fixture can be instanced by calling one of the strategies (attributesFor,
build, create):

```javascript
// This will create a plain javascript object with all of the defined attributes
const post = await fr.attributesFor("post");

// This will instantiate the class Post and assign all defined attributes onto it
const post = await fr.build("post");

// This will instantiate the class Post, assign all defined attributes as build does,
// and then save the instance to the database, according to the `save` function in the
// chosen adapter
const post = await fr.create("post");
```

Regardless of which strategy is used, the defined attributes can be overridden by
passing in an object as the final argument:

```javascript
const post = await fr.build("post", {title: "The best post in the universe"});
post.title === "The best post in the universe";
// > true
```

### Aliases
To make fixture reuse and specificity easier, fixtures can be defined with aliases:

Expand All @@ -156,7 +123,7 @@ fr.fixture("post", Post, {aliases: ["twit", "comment"]}, (f) => {
f.attr("body", () => "Thank you for reading.");
});

const comment = await fr.create("comment");
const comment = await fr.build("comment");
comment.title === "First post!";
// > true
```
Expand Down Expand Up @@ -207,8 +174,84 @@ fr.fixture("user", User, (f) => {
});

const user = await fr.build("user", {cool: true});
user.name === 'Noah "The Coolest Dude" Bogart';
// > true
user.name
// => 'Noah "The Coolest Dude" Bogart'
Reflect.has(user, "cool");
// > false
// => false
```

### Nested fixtures
By defining a fixture within a fixture, the child fixture will inherit and override any
declared attributes on the parent, all the way up the inheritance chain.

```javascript
fr.fixture("grandparentList", List, (f) => {
f.entry1(() => "100");
f.entry2(() => "200");

f.fixture("parentList", List, (ff) => {
ff.entry2(() => "20");
ff.entry3(() => "30");

ff.fixture("childList", List, (fff) => {
fff.entry3(() => "3");
});
});
});

const list = await fr.build("childList");
list.entry1
// => 100
list.entry2
// => 20
list.entry3
// => 3
```

The parent fixture can be specified instead of nesting:

```javascript
fr.fixture("parentList", List, (f) => {
f.attr("entry1", () => "10");
f.attr("entry2", () => "20");
});

fr.fixture("childList", List, {parent: "parentList"}, (f) => {
f.attr("entry2", () => "2");
f.attr("entry3", () => "3");
});

const list = await fr.build("childList");
list.entry1
// => 10
list.entry2
// => 2
list.entry3
// => 3
```

## Using fixtures
A defined fixture can be instanced by calling one of the strategies (attributesFor,
build, create):

```javascript
// This will create a plain javascript object with all of the defined attributes
const post = await fr.attributesFor("post");

// This will instantiate the class Post and assign all defined attributes onto it
const post = await fr.build("post");

// This will instantiate the class Post, assign all defined attributes as build does,
// and then save the instance to the database, according to the `save` function in the
// chosen adapter
const post = await fr.create("post");
```

Regardless of which strategy is used, the defined attributes can be overridden by
passing in an object as the final argument:

```javascript
const post = await fr.build("post", {title: "The best post in the universe"});
post.title
// => "The best post in the universe"
```
160 changes: 118 additions & 42 deletions test/acceptance/guide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,33 @@ describe.only("All of the code from the guide", function() {
});

describe("Defining fixtures", function() {
before(async function() {
beforeEach(async function() {
fr = new FixtureRiveter();
fr.setAdapter(new ObjectionAdapter());
});

specify("Explicit vs Implicit", async function() {
Post = await defineModel("Post", {
title: "string",
body: "string",
sequence: "string",
});


fr.fixture("post", Post, (f: any) => {
f.attr("title", () => "First post!");
f.body(() => "Thank you for reading.");
f.attr("sequence", () => "12345");
});

const post = await fr.create("post");

expect(post.title).to.equal("First post!");
expect(post.body).to.equal("Thank you for reading.");
expect(post.sequence).to.equal("12345");
});

specify("Dependent attributes", async function() {
User = await defineModel("User", {
firstName: "string",
lastName: "string",
Expand All @@ -71,6 +82,17 @@ describe.only("All of the code from the guide", function() {
f.lastName(() => "Bogart");
});

const user = await fr.create("user");
expect(user.email).to.equal("noah-bogart@example.com");
});

specify("Argument passing vs Context", async function() {
User = await defineModel("User", {
firstName: "string",
lastName: "string",
email: "string",
});

fr.fixture("contextUser", User, function() {
// eslint-disable-next-line no-invalid-this
this.firstName(() => "Noah");
Expand All @@ -85,55 +107,27 @@ describe.only("All of the code from the guide", function() {
return `${firstName}-${lastName}@example.com`.toLowerCase();
});
});
});

specify("Explicit vs Implicit", async function() {
const post = await fr.create("post");

expect(post.title).to.equal("First post!");
expect(post.body).to.equal("Thank you for reading.");
expect(post.sequence).to.equal("12345");
});

specify("Dependent attributes", async function() {
const user = await fr.create("user");
expect(user.email).to.equal("noah-bogart@example.com");
});

specify("Argument passing vs Context", async function() {
const user = await fr.create("contextUser");
expect(user.email).to.equal("noah-bogart@example.com");
});
});

describe("Using fixtures", function() {
beforeEach(async function() {
fr = new FixtureRiveter();
fr.setAdapter(new ObjectionAdapter());
Post = await defineModel("Post", {title: "string"});
fr.fixture("post", Post, (f: any) => f.title(() => "First post!"));
});

specify("attributesFor", async function() {
const post = await fr.attributesFor("post");
expect(post).to.not.be.an.instanceof(Post);
});
specify("aliases", async function() {
Post = await defineModel("Post", {
title: "string",
body: "string",
});

specify("build", async function() {
const post = await fr.build("post");
expect(post).to.be.an.instanceof(Post);
expect(post.id).to.be.undefined;
});
fr.fixture("post", Post, {aliases: ["twit", "comment"]}, (f) => {
f.attr("title", () => "First post!");
f.attr("body", () => "Thank you for reading.");
});

specify("create", async function() {
const post = await fr.create("post");
expect(post).to.be.an.instanceof(Post);
expect(post.id).to.exist;
});
const twit = await fr.build("twit");
expect(twit.title).to.equal("First post!");

specify("overriding attributes", async function() {
const post = await fr.build("post", {title: "The best post in the universe"});
expect(post.title).to.equal("The best post in the universe");
const comment = await fr.build("comment");
expect(comment.body).to.equal("Thank you for reading.");
});

specify("transient attributes", async function() {
Expand Down Expand Up @@ -178,5 +172,87 @@ describe.only("All of the code from the guide", function() {
expect(user.name).to.equal('Noah "The Coolest Dude" Bogart');
expect(Reflect.has(user, "cool")).to.be.false;
});

specify("nested fixtures", async function() {
const List = await defineModel("List", {
entry1: "string",
entry2: "string",
entry3: "string",
});

fr.fixture("grandparentList", List, (f: any) => {
f.attr("entry1", () => "100");
f.attr("entry2", () => "200");

f.fixture("parentList", List, (ff: any) => {
ff.entry2(() => "20");
ff.entry3(() => "30");

ff.fixture("childList", List, (fff: any) => {
fff.entry3(() => "3");
});
});
});

const list = await fr.build("childList");
expect(list.entry1).to.equal("100");
expect(list.entry2).to.equal("20");
expect(list.entry3).to.equal("3");
});

specify("nested fixtures with explicit parent", async function() {
const List = await defineModel("List", {
entry1: "string",
entry2: "string",
entry3: "string",
});

fr.fixture("parentList", List, (f) => {
f.attr("entry1", () => "10");
f.attr("entry2", () => "20");
});

fr.fixture("childList", List, {parent: "parentList"}, (f) => {
f.attr("entry2", () => "2");
f.attr("entry3", () => "3");
});

const list = await fr.build("childList");
expect(list.entry1).to.equal("10");
expect(list.entry2).to.equal("2");
expect(list.entry3).to.equal("3");
});
});

describe("Using fixtures", function() {
beforeEach(async function() {
fr = new FixtureRiveter();
fr.setAdapter(new ObjectionAdapter());
Post = await defineModel("Post", {title: "string"});
fr.fixture("post", Post, (f: any) => f.title(() => "First post!"));
});

specify("attributesFor", async function() {
const post = await fr.attributesFor("post");
expect(post).to.not.be.an.instanceof(Post);
});

specify("build", async function() {
const post = await fr.build("post");
expect(post).to.be.an.instanceof(Post);
expect(post.id).to.be.undefined;
});

specify("create", async function() {
const post = await fr.create("post");
expect(post).to.be.an.instanceof(Post);
expect(post.id).to.exist;
});

specify("overriding attributes", async function() {
const post = await fr.build("post", {title: "The best post in the universe"});
expect(post.title).to.equal("The best post in the universe");
});

});
});

0 comments on commit 4d531cf

Please sign in to comment.