Skip to content

Commit

Permalink
Acceptance Test POC and Setup (#41)
Browse files Browse the repository at this point in the history
* chore: Add tests workspace and ignore cypress gens

* build(acceptance-tests): setup cypress testing and typescript suppport

* test(acceptance-tests): add sample test for SignIn

* Update cucumber and cypress tests

* Revert lock file changes

* Update lock file with package changes

* Fix conflict

* Move acceptance-tests to packages/e2e

* Use aws-amplify@latest for all packages

* Add aws-amplify-react for testing

* Add @aws-amplify/ui-react-v1 for explicitly testing the previous version

* Update yarn.lock to match

* Sign In with valid/invalid credentials tests

* Ignore .env.local

* Prototype CONTRIBUTING.md

* Update ignored files and lockfile

* Add Cypress env variables and use scenario outline

* Remove acceptance-tests workspace

* Rename test to use .steps.ts and type button name

* Revert feature steps to separate explicit scenarios

* Render acceptance tests by convention

* Add `key` to prevent warnings

* Reconfigure .gitignore options

* Rename tests directory to conventional "integration"

* Replace dotenv with dotenv-safe

* Revert changes to SignIn component

* Rename example env file

* Remove unnecessary cypress-cucumber-preprocessor config option

* Update lockfile

* Remove ignored cypress dirs from root

* Fix path to feature tests

* Type featureTests

* Remove example.json from fixtuers/

* Organize imports

* Amplify typo

Co-authored-by: Eric Clemmons <eric@smarterspam.com>
  • Loading branch information
slaymance and ericclemmons authored Jun 23, 2021
1 parent 17dc3d9 commit ffc491a
Show file tree
Hide file tree
Showing 24 changed files with 3,331 additions and 1,493 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.DS_Store
.env
.env.local
*.log
node_modules
aws-exports.js
Expand Down
81 changes: 81 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Contributing

## Getting Started

1. Fork & Clone this repo
1. [`nvm install`](https://github.com/nvm-sh/nvm)
1. [`nvm use`](https://github.com/nvm-sh/nvm)
1. `yarn install`

## Documentation Development

1. Run the documentation via `yarn docs`
1. Visit <http://localhost:3000/>
1. Create/Update content based on the URL.

For example, the content for
http://localhost:3000/components/authenticator is located at [`docs/src/content/components/authenticator/index.mdx`](docs/src/content/components/authenticator/index.mdx)

Internally, this content is served by a single, Next.js [optional catch all route](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes):
[`docs/src/pages/[[...slugs]].tsx`](docs/src/pages/[[...slugs]].tsx).

## React Development

1. `yarn docs` to run the development server
1. Create or Update an example at [`docs/src/pages/component/authenticator/examples/...`](docs/src/pages/component/authenticator/examples)

```js
// .../authenticator/examples/sign-in.ts
import { Authenticator } from "aws-amplify-react";
import { Amplify } from "aws-amplify";
import "@aws-amplify/ui/dist/style.css";

// **You will need to provide this file yourself**
import awsExports from "./aws-exports";

Amplify.configure(awsExports);

export default function Example() {
return <Authenticator />;
}
```

1. Visit your example (.e.g. <http://localhost:3000/docs/src/pages/component/authenticator/examples/sign-in>)
1. Make changes to [`@aws-amplify/ui-react`](packages/react) & save.

Next.js should automatically hot-reload your changes in the example.

### Documentation & Testing

1. Create or Update a `${feature}.feature` file (using [Gherkin](https://cucumber.io/docs/gherkin/reference/)) describing the behavior in [`packages/e2e/cypress/tests/acceptance/${slug}`](packages/e2e/cypress/tests/acceptance).

```gherkin
Feature: My new feature
Documentation-friendly description of this feature, why it exists, & how to use it.
Scenario: Example scenario using this feature
Given some "STARTING_POINT"
When I DO "SOMETHING"
And I DO SOMETHING "ELSE"
Then I see "THE DESIRED BEHAVIOR"
```

1. Create or Update the accompanying `${slug}.feature` tests (e.g. `packages/e2e/cypress/tests/acceptance/${slug}/${feature}/${feature}.ts`
1. Run `yarn workspace e2e dev` to load Cypress
1. Click on your updated `${feature}.feature` file to validate your changes

#### Vue Development

1. `yarn dev:vue`
1. Visit <http://localhost:3001/>

#### Angular Development

1. `yarn build:angular`, or `yarn build:angular:watch` for live development
1. `yarn dev:angular`.
1. Visit <http://localhost:4200/>

#### Flutter Development

1. see [packages/flutter/README.md](packages/flutter/README.md)
29 changes: 1 addition & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,5 @@
## Documentation

The latest documentation is found here:
> https://docs.amplify.aws/ui
## Contributing

### Getting Started

1. Fork & Clone this repo
1. [`nvm use`](https://github.com/nvm-sh/nvm)
1. `yarn install`

#### React Development

1. `yarn dev`
1. Visit <http://localhost:3000/>

#### Vue Development

1. `yarn dev:vue`
1. Visit <http://localhost:3001/>

#### Angular Development

1. `yarn build:angular`, or `yarn build:angular:watch` for live development
1. `yarn dev:angular`.
1. Visit <http://localhost:4200/>

#### Flutter Development

1. see [packages/flutter/README.md](packages/flutter/README.md)
> https://docs.amplify.aws/ui
2 changes: 1 addition & 1 deletion angular-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@angular/platform-browser": "~11.2.5",
"@angular/platform-browser-dynamic": "~11.2.5",
"@angular/router": "~11.2.5",
"aws-amplify": "^3.3.25",
"aws-amplify": "latest",
"ngx-markdown": "^11.1.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
Expand Down
4 changes: 4 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
"start": "next start"
},
"dependencies": {
"@aws-amplify/ui-react-v1": "npm:@aws-amplify/ui-react",
"@cucumber/gherkin": "^19.0.3",
"@cucumber/messages": "^16.0.1",
"@headlessui/react": "^1.2.0",
"@heroicons/react": "^1.0.1",
"@mdx-js/loader": "^1.5.1",
"@mdx-js/react": "^1.6.18",
"@moxy/next-compile-node-modules": "^2.0.2",
"@next/mdx": "^9.1.1",
"aws-amplify": "latest",
"aws-amplify-react": "latest",
"gray-matter": "^4.0.3",
"mdx-prism": "^0.3.3",
"next": "latest",
Expand Down
33 changes: 33 additions & 0 deletions docs/src/components/FeatureTests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { GherkinDocument } from "@cucumber/messages";

interface FeatureTestsProps {
featureTests: GherkinDocument[];
}

export function FeatureTests({ featureTests = [] }: FeatureTestsProps) {
if (!featureTests.length) {
return null;
}

return (
<>
<h2>Features</h2>

{featureTests.map(({ feature }) => (
<section key={feature.name}>
<h3>{feature.name}</h3>
<p>{feature.description}</p>

<h4>Examples</h4>
<ul>
{feature.children.map(({ scenario }) => (
<li key={scenario.name}>
<a href="#">{scenario.name}</a>
</li>
))}
</ul>
</section>
))}
</>
);
}
2 changes: 2 additions & 0 deletions docs/src/content/components/authenticator/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ function App() {
export default withAuthenticator(App)
```

<FeatureTests featureTests={featureTests} />

## Authenticator with Default Theme

Amplify UI provides simple, clean styles to get started with a great experience in two steps:
Expand Down
12 changes: 11 additions & 1 deletion docs/src/pages/[[...slugs]].tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { customComponents } from "@/components/customComponents";
import { FeatureTests } from "@/components/FeatureTests";
import { Layout } from "@/components/Layout";
import { getContentPaths } from "@/utils/getContentPaths";
import { getFeatureTestsFromSlug } from "@/utils/getFeatureTestsFromSlug";
import { getPageFromSlug } from "@/utils/getPageFromSlug";
import * as components from "@aws-amplify/ui-react";
import { theme } from "@aws-amplify/ui-react";
import mdxPrism from "mdx-prism";
import { GetStaticPaths, GetStaticProps } from "next";
import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";

export default function Content({
featureTests = [],
frontmatter,
mdxSource,
componentPages,
Expand All @@ -23,7 +27,12 @@ export default function Content({
>
<MDXRemote
{...mdxSource}
components={{
...components,
FeatureTests,
}}
scope={{
featureTests,
theme,
customComponents,
}}
Expand Down Expand Up @@ -54,7 +63,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
});

const { content, frontmatter } = await getPageFromSlug(slug);

const featureTests = await getFeatureTestsFromSlug(slug);
const componentPagePaths = await getContentPaths("components/*/index.mdx");
const componentPages = await Promise.all(
componentPagePaths.map(getPageFromSlug).map(page => page.then(pluckMeta))
Expand Down Expand Up @@ -86,6 +95,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
props: {
frontmatter,
componentPages,
featureTests,
mdxSource,
primitivePages,
},
Expand Down
10 changes: 10 additions & 0 deletions docs/src/pages/components/authenticator/examples/sign-in.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Authenticator } from "aws-amplify-react";
import { Amplify } from "aws-amplify";
import "@aws-amplify/ui/dist/style.css";
import awsExports from "./aws-exports";

Amplify.configure(awsExports);

export default function Example() {
return <Authenticator />;
}
36 changes: 36 additions & 0 deletions docs/src/utils/getFeatureTestsFromSlug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
AstBuilder,
GherkinClassicTokenMatcher,
Parser,
} from "@cucumber/gherkin";
import { IdGenerator } from "@cucumber/messages";
import { readFile } from "fs/promises";
import glob from "glob";
import path from "path";

const parser = new Parser(
new AstBuilder(IdGenerator.uuid()),
new GherkinClassicTokenMatcher() // or GherkinInMarkdownTokenMatcher()
);

export async function getFeatureTestsFromSlug(slug: string) {
const cwd = path.join(
process.cwd(),
"../packages/e2e/cypress/integration",
slug
);

const featurePaths = glob.sync("**.feature", { cwd });
const featureFiles = await Promise.all(
featurePaths.map(featurePath =>
readFile(path.resolve(cwd, featurePath), "utf-8")
)
);

const featureTests = featureFiles.map(featureFile =>
parser.parse(featureFile)
);

// Strip `undefined` properties because they're not JSON-serializable by Next.js
return JSON.parse(JSON.stringify(featureTests));
}
2 changes: 1 addition & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@angular/platform-browser": "~11.2.4",
"@angular/platform-browser-dynamic": "~11.2.4",
"@angular/router": "~11.2.4",
"aws-amplify": "^3.3.25",
"aws-amplify": "latest",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.3"
Expand Down
4 changes: 4 additions & 0 deletions packages/e2e/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
INVALID_PASSWORD=
INVALID_USERNAME=
VALID_PASSWORD=
VALID_USERNAME=
3 changes: 3 additions & 0 deletions packages/e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# testing
cypress/screenshots
cypress/videos
4 changes: 4 additions & 0 deletions packages/e2e/cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"baseUrl": "http://localhost:3000/",
"testFiles": "**/*.feature"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Sign In

Amplify's SignIn component uses AWS Cognito's authentication
service to provide a sign in experience to your application's
users.

Scenario: Sign in with invalid credentials
Given I'm at the sign in page
When I type an invalid username "INVALID_USERNAME"
And I type an invalid password "INVALID_PASSWORD"
And I click the "Sign In" button
Then I see "User does not exist"

Scenario: Sign in with valid credentials
Given I'm at the sign in page
When I type a valid username "VALID_USERNAME"
And I type a valid password "VALID_PASSWORD"
And I click the "Sign In" button
Then I see "Hello VALID_USERNAME"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { And, Given, Then, When } from "cypress-cucumber-preprocessor/steps";

Given("I'm at the sign in page", () => {
cy.visit("/components/authenticator/examples/sign-in");
});

When("I type an invalid username {string}", (username: string) => {
cy.get("[data-test=username-input]").type(Cypress.env(username));
});

And("I type an invalid password {string}", (password: string) => {
cy.get("[data-test=sign-in-password-input]").type(Cypress.env(password));
});

And("I click the {string} button", (name: string) => {
cy.findByRole("button", { name }).click();
});

When("I type a valid username {string}", (username: string) => {
cy.get("[data-test=username-input]").type(Cypress.env(username));
});

And("I type a valid password {string}", (password: string) => {
cy.get("[data-test=sign-in-password-input]").type(Cypress.env(password));
});

Then("I see {string}", (message: string) => {
const [messageString, username] = message.split(" ");
cy.get("body").contains([messageString, Cypress.env(username)].join(" "));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@React
Feature: withAuthenticator

`withAuthenticator` is an easy way to wrap your entire application with authentiation.

```js{1,9}
import { withAuthenticator } from "@aws-amplify/ui-react"

function App() {
return (
...
)
}

export default withAuthenticator(App)
```

Example: Show the "Sign In" screen by default
Given an application wrapped with withAuthenticator
When I am not authenticated
Then I see a "Sign In" button
Loading

0 comments on commit ffc491a

Please sign in to comment.