Skip to content

Commit

Permalink
Add an API demo page with Netlify Dev and tested with Cypress
Browse files Browse the repository at this point in the history
  • Loading branch information
cedricss committed Jul 13, 2019
1 parent 5017690 commit 0bffa52
Show file tree
Hide file tree
Showing 10 changed files with 320 additions and 64 deletions.
11 changes: 0 additions & 11 deletions cypress/integration/404.spec.js

This file was deleted.

128 changes: 128 additions & 0 deletions cypress/integration/demo.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
context("Demo", () => {
/**
All tests are intentionally in the same file
You can dispatch the following contexts in multiple *.spec.js files
*/
context("Visit the homepage", () => {
beforeEach(() => {
cy.visit("/");
});

it("display the content related to this URL", () => {
/**
The Elm app uses data-* attributes to provide context to the selectors
and insulate them from CSS or JS changes.
https://docs.cypress.io/guides/references/best-practices.html
*/
cy.get("[data-test=content]").contains("Elm Batteries Included");
});

context("Open the API demo page from the menu bar", () => {
beforeEach(() => {
cy.get("[data-test=menu]")
.contains("API demo")
.click();
});

it("change the URL", () => {
cy.url().should("eq", Cypress.config().baseUrl + "/api/demo");
});

it("update the page with a new content", () => {
cy.get("[data-test=content]").contains("API demo");
});

it("go back to the homepage", () => {
cy.get("[data-test=logo]").click();
cy.get("[data-test=content]").contains("Elm Batteries Included");
});
});
});

context("Visit a page that doesn't exist", () => {
beforeEach(() => {
cy.visit("/xyz");
});

it("display the not found page", () => {
cy.get("[data-test=content]").contains(
"Sorry, we could not find this page."
);
});
});

context("Visit the API demo page", () => {
beforeEach(() => {
cy.visit("/api/demo");
cy.get("[data-test=package]").should(
"have.attr",
"data-result",
"not-asked"
);
});

it("display the content related to this URL", () => {
cy.get("[data-test=content]").contains("API demo");
});

it("show data from the API response", () => {
cy.server();

// We stub the call with another author
cy.route("/.netlify/functions/demo", {
name: "elm-batteries",
url: "https://elm-batteries.netlify.com",
author: "John Doe",
license: "MIT"
}).as("demo");

cy.get("[data-action=fetch-package]").click();

cy.wait("@demo");
cy.get("[data-value=author]").contains("John");
});

it("show an error if the API response is invalid", () => {
cy.server();

// We stub the call with an invalid empty response
cy.route("/.netlify/functions/demo", {}).as("demo");

cy.get("[data-action=fetch-package]").click();

cy.wait("@demo");
cy.get("[data-test=package]").should("have.attr", "data-result", "error");
});

/**
The request in the following test is not stubbed: it guarantees that the
contract between your Elm app and Netlify is working correctly.
https://docs.cypress.io/guides/guides/network-requests.html#Testing-Strategies
*/
it("reach the Netlify function and retrieve data", () => {
cy.server();
cy.route("/.netlify/functions/demo").as("demo");

cy.get("[data-action=fetch-package]").click();
cy.get("[data-test=package]").should(
"have.attr",
"data-result",
"loading"
);

cy.wait("@demo")
.its("status")
.should("equal", 200);

cy.get("[data-test=package]").should(
"have.attr",
"data-result",
"success"
);

cy.get("[data-value=name]").contains("elm-batteries");
cy.get("[data-value=author]").contains("Cédric Soulas");
cy.get("[data-value=license]").contains("MIT");
});
});
});
31 changes: 0 additions & 31 deletions cypress/integration/navigation.spec.js

This file was deleted.

7 changes: 6 additions & 1 deletion elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@
"elm-version": "0.19.0",
"dependencies": {
"direct": {
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
"elm/browser": "1.0.1",
"elm/core": "1.0.2",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/url": "1.0.0",
"elm-explorations/markdown": "1.0.0",
"krisajenkins/remotedata": "6.0.1",
"rtfeldman/elm-css": "16.0.1"
},
"indirect": {
"Skinney/murmur3": "2.0.8",
"elm/json": "1.1.3",
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2",
"rtfeldman/elm-hex": "1.0.0"
Expand Down
12 changes: 9 additions & 3 deletions functions/version/version.js → functions/demo/demo.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
const package = require("../../package.json");

// Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method
exports.handler = async (event, context) => {
try {
// Fake a long running request
await new Promise(resolve => setTimeout(resolve, 500));

return {
statusCode: 200,
body: JSON.stringify({ name: package.name, version: package.version })
body: JSON.stringify({
name: "elm-batteries",
url: "https://elm-batteries.netlify.com",
author: "Cédric Soulas",
license: "MIT"
})
// // more keys you can return:
// headers: { "headerName": "headerValue", ... },
// isBase64Encoded: true,
Expand Down
20 changes: 20 additions & 0 deletions scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,33 @@ h4 {
@apply font-semibold text-xl text-gray-800;
}

button {
@apply bg-indigo-600 rounded shadow;
@apply border-4 border-transparent;
@apply px-4 py-2;
@apply font-semibold text-white;
&:hover:not(:disabled) {
@apply bg-indigo-700;
}
&:disabled {
@apply bg-indigo-400;
}
&:focus {
@apply outline-none border-4 border-blue-300;
}
}

a {
@apply text-blue-600 font-semibold;
&:hover {
@apply text-blue-800;
}
}

.bg-transition {
transition: background-color ease-out 200ms;
}

.btn {
@apply bg-blue-100 rounded px-4 py-2;
}
Expand Down
30 changes: 30 additions & 0 deletions src/Data.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Data exposing (Package, packageDecoder)

import Json.Decode as Decode
exposing
( Decoder
, decodeString
, float
, int
, list
, nullable
, string
)
import Json.Decode.Pipeline exposing (hardcoded, optional, required)


type alias Package =
{ name : String
, url : String
, author : String
, license : String
}


packageDecoder : Decoder Package
packageDecoder =
Decode.succeed Package
|> required "name" string
|> required "url" string
|> required "author" string
|> required "license" string
Loading

0 comments on commit 0bffa52

Please sign in to comment.