-
- {siteConfig.title}
-
- {idx(translation, [
- this.props.language,
- 'localized-strings',
- 'tagline',
- ]) || siteConfig.tagline}
-
-
-
-
-
-
- Try Out Jest
-
-
- Get Started
-
-
- Watch Talks
-
-
- Learn More
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RUNS
+
+
+
+
+ RUNS
+
+
+
+
+ RUNS
+
+
+
+
+ RUNS
+
+
+
+
@@ -197,6 +205,53 @@ class HomeSplash extends React.Component {
}
}
+class Hand extends React.Component {
+ render() {
+ const cards = [0, 1, 2, 3, 4].map(i =>
);
+ return (
+
+ {cards}
+
+
+ );
+ }
+}
+
+const HeroInteractive = ({config: {repoUrl}, language}) => (
+
+
+
+
+
+
+ Get Started
+
+
+ Docs
+
+
+ Config
+
+
+ Get help
+
+
+
+
+);
+
class Index extends React.Component {
render() {
const showcase = siteConfig.users.map((user, i) => (
@@ -207,258 +262,287 @@ class Index extends React.Component {
return (
-
-
-
+
+
+
+
+
+ Jest is a delightful JavaScript Testing Framework with a focus
+ on simplicity.
+
+
+
+
+
+ It works with projects using: [Babel](https://babeljs.io/),
+ [TypeScript](https://www.typescriptlang.org/),
+ [Node](https://nodejs.org/en/), [React](https://reactjs.org),
+ [Angular](https://angularjs.org), [Vue](https://vuejs.org) and
+ more!
+
+
+
+
+
- Complete and ready to set-up JavaScript testing solution.
- Works out of the box for any React project.
+ Jest aims to work out of the box, config free, on most
+ JavaScript projects.
),
- image: '/img/content/female-technologist.png',
- imageAlign: 'top',
- title: Developer Ready ,
+ title: Zero config ,
},
{
content: (
- Fast interactive watch mode runs only test files related
- to changed files and is optimized to give signal quickly.
+ Make tests which keep track of large objects with ease.
+ Snapshots live either alongside your tests, or embedded
+ inline.
),
- image: '/img/content/runner.png',
- imageAlign: 'top',
- title: Instant Feedback ,
+ title: Snapshots ,
},
{
content: (
- Capture snapshots of React trees or other serializable
- values to simplify testing and to analyze how state
- changes over time.
+ Tests runs parallel in their own processes to maximize
+ performance.
),
- image: '/img/content/camera-with-flash.png',
- imageAlign: 'top',
- title: Snapshot Testing ,
+ title: Isolated ,
},
- ]}
- layout="fourColumn"
- />
-
-
-
-
- Zero configuration testing platform
-
-
-
- Jest is used by Facebook to test all JavaScript code including
- React applications. One of Jest's philosophies is to provide
- an integrated \"zero-configuration\" experience. We observed
- that when engineers are provided with ready-to-use tools, they
- end up writing more tests, which in turn results in more
- stable and healthy code bases.
-
-
-
-
-
-
- Jest parallelizes test runs across workers to maximize
- performance. Console messages are buffered and printed
- together with test results. Sandboxed test files and
- automatic global state resets for every test so no two
- tests conflict with each other.
+ From `it` to `expect` - Jest has the entire toolkit in one
+ place. Well documented, well maintained, well good.
),
- image: '/img/content/feature-fast.png',
- imageAlign: 'right',
- title: Fast and sandboxed ,
+ title: Great api ,
},
]}
+ layout="fourColumn"
/>
-
+
+
- Easily create code coverage reports using
- [`--coverage`](https://jestjs.io/docs/en/cli.html#coverage).
- No additional setup or libraries needed! Jest can collect
- code coverage information from entire projects, including
- untested files.
+ By ensuring your tests have unique global state, Jest can
+ reliably run tests in parallel. To make things quick, Jest
+ runs previously failed tests first and re-organizes runs
+ based on how long test files take.
),
- image: '/img/content/feature-coverage.png',
+ image: '/img/content/feature-fast.png',
imageAlign: 'left',
- title: Built-in code coverage reports ,
+ title: Fast and safe ,
},
]}
/>
+ {/* Wondering where the image + buttons come from? That's client-side code in landing.js */}
-
+
- Jest is already configured when you use
- [`create-react-app`](https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html)
- or [`react-native
- init`](http://facebook.github.io/react-native/docs/getting-started.html)
- to create your React and React Native projects. Place your
- tests in a `__tests__` folder, or name your test files
- with a `.spec.js` or `.test.js` extension. Whatever you
- prefer, Jest will find and run your tests.
+ Generate code coverage by adding the flag
+ [`--coverage`](https://jestjs.io/docs/en/cli.html#coverage).
+ No additional setup needed. Jest can collect code coverage
+ information from entire projects, including untested
+ files.
),
- image: '/img/content/feature-config-react.png',
+ image: '/img/content/feature-coverage.png',
imageAlign: 'right',
- title: Zero configuration ,
+ title: Code coverage ,
},
]}
/>
-
-
-
-
-
-
- Try it out!
-
-
-
-
- You can try out a real version of Jest using
- [repl.it](https://repl.it/languages/jest). Consider a
- function, `add()`, that adds two numbers. We can use a
- basic test in `add-test.js` to verify that 1 + 2 equals 3.
- Hit \"run\" to try it out!
-
-
-
-
-
-
-
-
-
-
-
+
- Powerful [mocking library](/docs/en/mock-functions.html)
- for functions and modules. Mock React Native components
- using `jest-react-native`.
+ Jest uses a custom resolver for imports in your tests
+ making it simple to mock any object outside of your test’s
+ scope. You can use mocked imports with the rich [Mock
+ Functions](https://jestjs.io/docs/en/mock-functions.html)
+ API to spy on function calls with readable test syntax.
),
image: '/img/content/feature-mocking.png',
imageAlign: 'left',
- title: Powerful mocking library ,
+ title: Easy Mocking ,
},
]}
/>
-
-
+
- Jest works with any compile-to-JavaScript language and
- integrates seamlessly with [Babel](https://babeljs.io)
- which means you can write React, TypeScript and much more
- without configuration
+ Tests fail, when they do Jest provides rich context why,
+ here’s some examples:
),
- image: '/img/content/feature-typescript.png',
+ image: '/img/content/matchers/different-types.png',
imageAlign: 'right',
- title: Works with TypeScript ,
+ title: Great Exceptions ,
},
]}
/>
-
-
-
-
-
-
-
VIDEO
+
+
+
+
+
+
+ Jest is a JavaScript testing framework designed to ensure
+ correctness of any JavaScript codebase. It allows you to
+ write tests with an approachable, familiar and feature-rich
+ API that gives you results quickly.
+
+
+
+
+
+
+ Jest is well-documented, requires little configuration and
+ can be extended to match your requirements.
+
+
+
+ Jest makes testing delightful.
+
+
+
+
+
+
+
+
+
- Watch Talks about Jest
+ Docs and talks
-
+
+
+ The Jest core team and contributors regularly speak about
+ [Jest and Delightful JavaScript
+ Testing](https://www.youtube.com/watch?v=cAKYQpTC7MA). Check
+ out our talk about [Building High-Quality JavaScript
+ Tools](https://www.youtube.com/watch?v=PvabBs_utr8) at
+ jsconf.eu 2017 and our talk about [Jest as a
+ Platform](https://www.youtube.com/watch?v=NtjyeojAOBs) at
+ ReactiveConf 2017.
+
+
+
+
+
+
+
+
+
+
+
+ Open Collective
+
+
+
+ With so many users, the core team of Jest uses an [Open
+ Collective](https://opencollective.com/jest) for
+ non-Facebook contributors.
+
+
+
+
+
+
+ Who uses Jest?
+
- The Jest core team and contributors regularly speak about
- [Jest and Delightful JavaScript
- Testing](https://www.youtube.com/watch?v=cAKYQpTC7MA).
- Check out our talk about [Building High-Quality JavaScript
- Tools](https://www.youtube.com/watch?v=PvabBs_utr8) at
- jsconf.eu 2017 and our talk about [Jest as a
- Platform](https://www.youtube.com/watch?v=NtjyeojAOBs) at
- ReactiveConf 2017.
+ A lot of people! With
+ [8.5m](https://www.npmjs.com/package/jest) downloads in
+ the last 30 days, and used on over
+ [500,000](https://github.com/facebook/jest/network/dependents)
+ public repos on GitHub. Jest is used extensively at these
+ companies:
+
+ {showcase}
+
And many others
+
-
-
-
-
-
-
- Who's using Jest?
-
-
-
- Jest is used by teams of all sizes to test web applications,
- node.js services, mobile apps, and APIs.
-
-
-
{showcase}
-
diff --git a/website/siteConfig.js b/website/siteConfig.js
index bf9aa6270247..42ca63906008 100644
--- a/website/siteConfig.js
+++ b/website/siteConfig.js
@@ -53,7 +53,6 @@ const users = [
image: '/img/logos/facebook.png',
infoLink: 'https://code.facebook.com',
},
-
{
caption: 'Twitter',
image: '/img/logos/twitter.png',
@@ -119,8 +118,8 @@ const siteConfig = {
},
gaTrackingId: 'UA-44373548-17',
colors: {
- primaryColor: '#99424f',
- secondaryColor: '#7f2c39',
+ primaryColor: '#10910e',
+ secondaryColor: '#095708',
prismColor: 'rgba(153, 66, 79, 0.03)',
},
scripts: ['https://buttons.github.io/buttons.js'],
diff --git a/website/static/css/custom.css b/website/static/css/custom.css
index a0707d51284f..6716435b6495 100644
--- a/website/static/css/custom.css
+++ b/website/static/css/custom.css
@@ -1,5 +1,14 @@
/* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. */
+.mainContainer a {
+ text-decoration: underline;
+}
+
+.mainContainer a:hover,
+.mainContainer a:active {
+ text-decoration: none;
+}
+
.fixedHeaderContainer header img.logo {
height: 60px;
margin-top: -20px;
@@ -7,13 +16,12 @@
margin-right: -20px;
}
-.fixedHeaderContainer header .headerTitleWithLogo {
- font-size: 1.1em;
+#languages-dropdown-items a {
+ color: white;
}
-.fixedHeaderContainer header h3 {
- font-size: 14px;
- text-decoration: none;
+#languages-dropdown-items a:hover {
+ color: var(--green);
}
div.jest-repl {
@@ -21,41 +29,39 @@ div.jest-repl {
position: relative;
width: 600px;
}
+
div.jest-repl iframe {
display: block;
margin: 0 auto 10px;
min-height: 420px;
width: 100%;
}
-@media only screen and (min-device-width: 360px) and (max-device-width: 736px) {
- div.jest-repl {
- display: none;
- }
+
+div.bottom-margin {
+ margin-bottom: 40px;
}
-@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
- div.jest-repl {
- display: none;
- }
+
+.docs .wrapper {
+ display: flex;
}
-@media only screen and (max-width: 1023px) {
- div.jest-repl {
- display: none;
- }
+
+.docs .blockElement {
+ width: 50%;
}
-div.video {
- margin: 0 5%;
- position: relative;
+.blockContent div.video {
width: 100%;
- min-width: 300px;
- max-width: 600px;
+ height: 280px;
+ margin-top: 20px;
+ padding-right: 80px;
}
div.video iframe {
display: block;
margin: 0 auto 10px;
- min-height: 340px;
+ min-height: 280px;
width: 100%;
+ height: auto;
}
@media only screen and (min-device-width: 360px) and (max-device-width: 736px) {
@@ -63,8 +69,286 @@ div.video iframe {
display: none;
}
}
+
@media only screen and (max-width: 1023px) {
- div.video {
+ div.video,
+ div.video-block {
display: none;
}
+
+ .docs .blockElement {
+ width: 100%;
+ }
+}
+
+div.jest-hero-interactive {
+ position: relative;
+}
+
+div.hero-github-button-container {
+ min-height: 20px;
+ position: absolute;
+ left: initial;
+ right: 10px;
+ top: 20px;
+ visibility: hidden;
+ z-index: 1000;
+}
+
+/* Means the links doesn't push the vertical */
+.hash-link {
+ position: absolute;
+}
+
+@media only screen and (min-width: 580px) {
+ div.hero-github-button-container {
+ visibility: visible;
+ }
+}
+
+div.jest-hand {
+ width: 100%;
+ height: 350px;
+ display: flex;
+ justify-content: center;
+ overflow: hidden;
+ position: relative;
+ perspective: 1000px;
+}
+
+div.jest-card-hitslop {
+ cursor: pointer;
+ position: absolute;
+ transform-origin: 50% 100%;
+ height: 400px;
+}
+
+div.jest-card {
+ position: relative;
+ top: 60px;
+ width: 240px;
+ height: 340px;
+ transition: transform 0.2s;
+ transform-style: preserve-3d;
+}
+
+div.jest-card-front,
+.jest-card-back {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ border-radius: 15px;
+ backface-visibility: hidden;
+ pointer-events: none;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+div.jest-card-front {
+ background-color: #fff;
+ border: 1px solid #bbb;
+}
+
+div.jest-card-back {
+ background-color: #c2a813;
+ background-image: url(/img/running-card-background.png);
+ background-size: 20px;
+ border: 5px solid #c2a813;
+ backface-visibility: hidden;
+ transform: rotateY(180deg) translateZ(1px);
+}
+
+div.jest-card-running {
+ cursor: auto;
+ transform: translateY(-10px) rotateY(180deg);
+}
+
+div.jest-card-hitslop:hover
+ div.jest-card:not(.jest-card-running):not(.jest-card-pass) {
+ transform: translateY(-40px);
+}
+
+div.jest-card.jest-card-popping {
+ transform: translateY(-50px);
+}
+
+div.jest-card-hitslop:nth-child(1) {
+ visibility: hidden;
+}
+
+div.jest-card-hitslop:nth-child(3) {
+ z-index: 2;
+}
+
+div.jest-card-hitslop:nth-child(4) {
+ z-index: 1;
+}
+
+div.jest-card-hitslop:nth-child(5) {
+ visibility: hidden;
+}
+
+@media only screen and (min-width: 580px) {
+ div.jest-card-hitslop:nth-child(1) {
+ visibility: visible;
+ }
+
+ div.jest-card-hitslop:nth-child(5) {
+ visibility: visible;
+ }
+}
+
+div.jest-button-container {
+ position: absolute;
+ bottom: 0;
+ background-color: rgba(255, 255, 255, 0.5);
+ width: 100%;
+ margin: 0 auto;
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+a.jest-button {
+ text-transform: uppercase;
+ color: #fff;
+ background-color: var(--red);
+ margin: 10px;
+ padding: 0 1em;
+ font-size: 16px;
+ line-height: 2.2em;
+}
+
+a.jest-button:hover,
+a.jest-button:active {
+ background-color: #910e1b;
+}
+
+div.jest-card-label {
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ color: white;
+ background-color: var(--red);
+ font-size: 16px;
+ font-weight: bold;
+ display: inline;
+ padding: 0 0.5em;
+}
+
+div.jest-card-label.jest-card-label-reverse {
+ color: white;
+ top: auto;
+ left: auto;
+ bottom: 15px;
+ right: 15px;
+ transform: rotateX(180deg);
+}
+
+div.jest-card-logo-container {
+ width: 120px;
+ height: 120px;
+}
+
+div.jest-card-logo {
+ width: 100%;
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 80% 80%;
+}
+
+div.jest-card-pass {
+ cursor: auto;
+}
+
+div.jest-card-pass .jest-card-label,
+div.jest-card-run .jest-card-label {
+ background-color: var(--green);
+}
+
+div.jest-card-pass .jest-card-logo-container {
+ background-color: var(--green);
+ transform: rotate(45deg);
+}
+
+div.jest-card-pass .jest-card-logo {
+ width: 90%;
+ height: 90%;
+ background-image: url(/img/jest-card-pass.svg);
+ transform: rotate(-65deg);
+ background-size: 65% 65%;
+ background-position: 50% 75%;
+}
+
+div.jest-card-fail .jest-card-logo-container {
+ background-color: var(--red);
+}
+
+div.jest-card-fail .jest-card-logo {
+ background-position: 50% 65%;
+ background-size: 65% 65%;
+ background-image: url(/img/jest-card-fail.svg);
+}
+
+div.jest-card-run .jest-card-logo-container {
+ background-color: white;
+}
+
+div.jest-card-run .jest-card-logo {
+ background-image: url(/img/jest-card-run.svg);
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes undulate {
+ 0% {
+ transform: scale(0.8);
+ }
+ 50% {
+ transform: scale(1);
+ }
+ 90% {
+ transform: scale(0.9);
+ }
+ 100% {
+ transform: scale(0.8);
+ }
+}
+
+g.run-text {
+ transform-origin: 50% 50%;
+ animation-name: spin;
+ animation-duration: 5s;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+}
+
+circle.run-circle {
+ transform-origin: 50% 50%;
+ animation-name: undulate;
+ animation-duration: 3s;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+}
+
+circle.run-circle:nth-child(1) {
+ animation-delay: -1s;
+}
+circle.run-circle:nth-child(2) {
+ animation-delay: -2.2s;
+}
+circle.run-circle:nth-child(3) {
+ animation-delay: -2.6s;
+}
+circle.run-circle:nth-child(4) {
+ animation-delay: -3.3s;
}
diff --git a/website/static/css/hljs-jest.css b/website/static/css/hljs-jest.css
new file mode 100644
index 000000000000..bc43a2bda27a
--- /dev/null
+++ b/website/static/css/hljs-jest.css
@@ -0,0 +1,107 @@
+/* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. */
+
+/*
+Jest's Color Scheme for Highlight JS
+(c) The Jest Core Team
+
+/cc orta.therox+jest@gmail.com
+*/
+
+body .hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #f6f6f6;
+ border-left: 2px solid #d0d4c7;
+ color: black;
+}
+
+/* Gray DOCTYPE selectors like WebKit */
+body .xml .hljs-meta {
+ color: #b3b3b3;
+}
+
+body .hljs-comment,
+body .hljs-quote {
+ color: #65737e;
+}
+
+body .hljs-tag,
+body .hljs-attribute,
+body .hljs-keyword,
+body .hljs-selector-tag,
+body .hljs-literal,
+body .hljs-name {
+ color: #297a29;
+}
+
+body .hljs-variable,
+body .hljs-template-variable {
+ color: #3f6e74;
+}
+
+body .hljs-code,
+body .hljs-string,
+body .hljs-meta-string {
+ color: #c21325;
+}
+
+body .hljs-regexp,
+body .hljs-link {
+ color: #0e0eff;
+}
+
+body .hljs-title,
+body .hljs-symbol,
+body .hljs-bullet,
+body .hljs-number {
+ color: #1373c2;
+}
+
+body .hljs-section,
+body .hljs-meta {
+ color: #643820;
+}
+
+body .hljs-class .hljs-title,
+body .hljs-type,
+body .hljs-built_in,
+body .hljs-builtin-name,
+body .hljs-params {
+ color: #6b2e85;
+}
+
+body .hljs-attr {
+ color: #82772c;
+}
+
+body .hljs-subst {
+ color: #000;
+}
+
+body .hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+body .hljs-addition {
+ background-color: #baeeba;
+}
+
+body .hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+body .hljs-selector-id,
+body .hljs-selector-class {
+ color: #12a190;
+}
+
+body .hljs-doctag,
+body .hljs-strong {
+ font-weight: bold;
+}
+
+body .hljs-emphasis {
+ font-style: italic;
+}
diff --git a/website/static/css/jest.css b/website/static/css/jest.css
index 7da722ede050..b49c6e5c26c2 100644
--- a/website/static/css/jest.css
+++ b/website/static/css/jest.css
@@ -1,9 +1,26 @@
/* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. */
+:root {
+ --yellow: #c2a813;
+ --green: #15c213;
+ --red: #c21325;
+ --grey: #aaaaaa;
+ --grey2: #ededed;
+ --grey3: #545454;
+}
+
+.debug * {
+ outline: 1px solid rebeccapurple;
+}
+
.sponsor-item {
margin: 10px;
}
+.sponsor-item img {
+ background: #095708;
+}
+
.sponsor-avatar {
display: inline-block;
width: 100px;
@@ -44,3 +61,230 @@
background: #99424f;
color: #ffffff;
}
+
+.opencollective h3 {
+ display: inline-block;
+ font-weight: normal;
+ color: var(--yellow);
+ letter-spacing: 1px;
+ text-transform: lowercase;
+}
+
+.section-container .blockContent h2 {
+ display: inline-block;
+ font-size: 2rem;
+ font-weight: normal;
+ text-transform: uppercase;
+ padding-left: 10px;
+ margin-top: 1.6rem;
+ letter-spacing: 1px;
+ border-left-width: 8px;
+ border-left-style: solid;
+}
+
+.blockContent > div {
+ margin: 16px 0 0 18px;
+}
+
+.container.intro p {
+ font-size: 1.8rem;
+ font-family: Monaco, Courier, monospace;
+ color: var(--grey3);
+}
+
+.container.intro .wrapper {
+ max-width: 960px;
+}
+.container .wrapper .imageAlignSide p {
+ margin-bottom: 0;
+}
+
+/* On mobile, show the screenshot under the body */
+@media only screen and (max-width: 780px) {
+ /* Ensure the consistent order of text first, then image */
+ .container .wrapper .imageAlignLeft {
+ flex-flow: row wrap-reverse;
+ }
+
+ /* Makes the image is alway visible and has space to center correctly */
+ .imageAlignSide .blockImage {
+ display: block;
+ max-width: 100%;
+ flex: 0 1 100%;
+ margin: 0;
+ }
+
+ /* Makes sure that it's always centered */
+ .imageAlignSide .blockImage img {
+ margin: auto 0;
+ }
+}
+
+.container.section-container {
+ padding: 20px 0 0 0;
+}
+
+.container.section-container.philosophy {
+ padding: 30px 0;
+}
+
+.blockContent.flex-end {
+ align-self: flex-end;
+}
+
+.section-container .blockImage {
+ overflow: hidden;
+ height: 280px;
+}
+
+.container.features .yellow.blockElement h2,
+.container.features .yellow.blockElement p {
+ text-align: left;
+ margin: 16px 0 0 18px;
+}
+
+.section-container .blockImage img {
+ padding-top: 10px;
+}
+
+.logos {
+ align-items: center;
+}
+
+@media only screen and (min-width: 736px) {
+ /* Medium desktop and up */
+ .container .yellow.blockElement {
+ width: 25%;
+ }
+}
+
+.gridBlock.philosophy > *:first-child,
+.gridBlock.logos > *:first-child {
+ margin-left: 0;
+}
+
+.logos img {
+ max-height: 56px;
+ padding: 10px;
+ width: 56px;
+}
+
+.gridBlock > *:first-child {
+ margin: 0 12px;
+}
+
+.fixedHeaderContainer {
+ background-color: #ffffff;
+}
+
+.headerWrapper img {
+ display: none;
+}
+
+/* Section titles colors */
+.section-container .yellow h2 {
+ font-family: Monaco, Courier, monospace;
+ color: var(--yellow);
+}
+
+.section-container .green h2 {
+ font-family: Monaco, Courier, monospace;
+ color: var(--green);
+}
+
+.section-container .red h2 {
+ font-family: Monaco, Courier, monospace;
+ color: var(--red);
+}
+
+/* Search input background color */
+.reactNavSearchWrapper input#search_input_react {
+ background-color: var(--grey);
+}
+
+/* Logo */
+.headerTitleWithLogo {
+ background-color: var(--green);
+ text-transform: uppercase;
+ color: var(--grey2);
+ padding: 6px 15px;
+}
+
+.container.features {
+ padding: 40px 0;
+}
+
+.features .gridBlock {
+ flex-wrap: nowrap;
+}
+
+.features .gridBlock .fourByGridBlock {
+ flex: initial;
+}
+
+.features h2 {
+ color: var(--yellow);
+ font-size: 20px;
+ text-transform: lowercase;
+ font-family: Monaco, Courier, monospace;
+}
+
+.features .blockElement {
+ margin: 0;
+}
+
+.button.landing {
+ margin: 4px 10px;
+ cursor: pointer;
+}
+
+.container .gridBlock .blockContent p.buttons-wrapper {
+ margin: 8px;
+}
+
+.button.landing.active {
+ background: var(--green);
+ color: #fff;
+}
+
+.navigationSlider .slidingNav ul li a,
+.fixedHeaderContainer header h3 {
+ color: var(--grey3);
+}
+
+div.navigationSlider .slidingNav ul {
+ background: #ffffff;
+}
+
+.navigationSlider .slidingNav ul li a:focus,
+.navigationSlider .slidingNav ul li a:hover,
+.navigationSlider .slidingNav ul li.siteNavGroupActive a {
+ background: #ffffff;
+ color: var(--grey3);
+}
+
+body
+ > div.fixedHeaderContainer
+ > div
+ > header
+ > div
+ > nav
+ > ul
+ > li.siteNavGroupActive.siteNavItemActive
+ > a {
+ background-color: #10910e;
+ color: white;
+}
+
+.hide-small {
+ display: none;
+}
+
+@media only screen and (min-width: 736px) {
+ .show-small {
+ display: none;
+ }
+ .hide-small {
+ display: block;
+ }
+}
diff --git a/website/static/img/content/feature-config-react.png b/website/static/img/content/feature-config-react.png
deleted file mode 100644
index 5cecd05b40b7..000000000000
Binary files a/website/static/img/content/feature-config-react.png and /dev/null differ
diff --git a/website/static/img/content/feature-coverage.png b/website/static/img/content/feature-coverage.png
index 90d8d8d82cca..e50e286d0178 100644
Binary files a/website/static/img/content/feature-coverage.png and b/website/static/img/content/feature-coverage.png differ
diff --git a/website/static/img/content/feature-fast.png b/website/static/img/content/feature-fast.png
index 08600ee38b9b..3491675e264e 100644
Binary files a/website/static/img/content/feature-fast.png and b/website/static/img/content/feature-fast.png differ
diff --git a/website/static/img/content/feature-mocking.png b/website/static/img/content/feature-mocking.png
index 7988be27f075..3ba1ff4c5949 100644
Binary files a/website/static/img/content/feature-mocking.png and b/website/static/img/content/feature-mocking.png differ
diff --git a/website/static/img/content/feature-typescript.png b/website/static/img/content/feature-typescript.png
deleted file mode 100644
index c1b155441385..000000000000
Binary files a/website/static/img/content/feature-typescript.png and /dev/null differ
diff --git a/website/static/img/content/matchers/different-types.png b/website/static/img/content/matchers/different-types.png
new file mode 100644
index 000000000000..e6b6061c1201
Binary files /dev/null and b/website/static/img/content/matchers/different-types.png differ
diff --git a/website/static/img/content/matchers/equals.png b/website/static/img/content/matchers/equals.png
new file mode 100644
index 000000000000..7f4507fa12e2
Binary files /dev/null and b/website/static/img/content/matchers/equals.png differ
diff --git a/website/static/img/content/matchers/functions.png b/website/static/img/content/matchers/functions.png
new file mode 100644
index 000000000000..3a91599c4157
Binary files /dev/null and b/website/static/img/content/matchers/functions.png differ
diff --git a/website/static/img/content/matchers/inline-snapshot.png b/website/static/img/content/matchers/inline-snapshot.png
new file mode 100644
index 000000000000..1ddd2395f4a5
Binary files /dev/null and b/website/static/img/content/matchers/inline-snapshot.png differ
diff --git a/website/static/img/content/matchers/missing-properties.png b/website/static/img/content/matchers/missing-properties.png
new file mode 100644
index 000000000000..727d8d67c5f4
Binary files /dev/null and b/website/static/img/content/matchers/missing-properties.png differ
diff --git a/website/static/img/content/matchers/mocks.png b/website/static/img/content/matchers/mocks.png
new file mode 100644
index 000000000000..895b8693737a
Binary files /dev/null and b/website/static/img/content/matchers/mocks.png differ
diff --git a/website/static/img/content/matchers/snapshot.png b/website/static/img/content/matchers/snapshot.png
new file mode 100644
index 000000000000..db241a212399
Binary files /dev/null and b/website/static/img/content/matchers/snapshot.png differ
diff --git a/website/static/img/jest-badge.svg b/website/static/img/jest-badge.svg
index 344600c3a628..5642e7d43157 100644
--- a/website/static/img/jest-badge.svg
+++ b/website/static/img/jest-badge.svg
@@ -1 +1 @@
-Jest Jest
\ No newline at end of file
+Jest Jest
diff --git a/website/static/img/jest-card-fail.svg b/website/static/img/jest-card-fail.svg
new file mode 100644
index 000000000000..dd20f3bfd4a4
--- /dev/null
+++ b/website/static/img/jest-card-fail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website/static/img/jest-card-pass.svg b/website/static/img/jest-card-pass.svg
new file mode 100644
index 000000000000..cf5bbb413fab
--- /dev/null
+++ b/website/static/img/jest-card-pass.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website/static/img/jest-card-run.svg b/website/static/img/jest-card-run.svg
new file mode 100644
index 000000000000..9f42869c31fa
--- /dev/null
+++ b/website/static/img/jest-card-run.svg
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website/static/img/jest.svg b/website/static/img/jest.svg
index 8e0234c32767..ea5b5dcd7b81 100644
--- a/website/static/img/jest.svg
+++ b/website/static/img/jest.svg
@@ -1,13 +1,13 @@
-
+
-
+
-
+
-
+
-
+
-
\ No newline at end of file
+
diff --git a/website/static/img/running-card-background.png b/website/static/img/running-card-background.png
new file mode 100644
index 000000000000..d08e5f32ea72
Binary files /dev/null and b/website/static/img/running-card-background.png differ
diff --git a/website/static/landing.js b/website/static/landing.js
new file mode 100644
index 000000000000..e2a28f0f3fc0
--- /dev/null
+++ b/website/static/landing.js
@@ -0,0 +1,210 @@
+/* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. */
+
+/* global document, window, localStorage */
+
+// Allow taking a bit longer on the first run
+const firstRun = localStorage.getItem('firstRun');
+localStorage.setItem('firstRun', 'true');
+const baseMinimalTime = firstRun ? 3000 : 1500;
+
+document.addEventListener('DOMContentLoaded', () => {
+ const hand = document.querySelector('.jest-hand');
+ const cards = hand.querySelectorAll('.jest-card');
+
+ function cardTransform(offset, handWidth) {
+ const transform =
+ 'rotate(' +
+ offset * 4 +
+ 'deg) translateX(' +
+ (offset - (Math.abs(offset) * offset) / 7) *
+ Math.min(140, handWidth / 8) +
+ 'px)';
+ return transform;
+ }
+
+ function positionCards() {
+ const handWidth = hand.offsetWidth;
+ cards.forEach(card => {
+ const offset = parseInt(card.dataset.index, 10) - 2;
+ card.parentElement.style.transform = cardTransform(offset, handWidth);
+ });
+ }
+
+ const results = [];
+ const timeouts = [];
+
+ function resolveRun(card, index, minTime) {
+ minTime = minTime || 500;
+ setTimeout(() => {
+ if (index === 2) {
+ results[index] = null;
+ card.classList.add('jest-card-run');
+ } else if (results[index]) {
+ card.classList.remove('jest-card-fail');
+ card.classList.add('jest-card-pass');
+ card.querySelectorAll('.jest-card-label').forEach(el => {
+ el.innerHTML = 'PASS';
+ });
+ } else {
+ card.classList.remove('jest-card-pass');
+ card.classList.add('jest-card-fail');
+ card.querySelectorAll('.jest-card-label').forEach(el => {
+ el.innerHTML = 'FAIL';
+ });
+ }
+ }, minTime);
+
+ if (timeouts[index]) {
+ clearTimeout(timeouts[index]);
+ }
+
+ timeouts[index] = setTimeout(
+ () => {
+ card.classList.remove('jest-card-running');
+ card.classList.add('jest-card-popping');
+ setTimeout(() => {
+ results[index] = results[index] || null;
+ card.classList.remove('jest-card-popping');
+ }, 400);
+ },
+ index === 2
+ ? baseMinimalTime + minTime
+ : Math.random() * baseMinimalTime + minTime
+ );
+ }
+
+ function forceRun(minTime) {
+ let fails = 0;
+ cards.forEach((card, index) => {
+ card.classList.add('jest-card-running');
+ const result = index === 2 || fails > 1 || Math.random() > 0.25;
+ if (!result) {
+ fails += 1;
+ }
+ results[index] = result;
+ resolveRun(card, index, minTime);
+ });
+ }
+
+ function runTest(card, index) {
+ if (!card.classList.contains('jest-card-running') && !results[index]) {
+ if (index === 2) {
+ return forceRun(1000);
+ }
+ card.classList.add('jest-card-running');
+ if (results[index] == null) {
+ results[index] = Math.random() > 0.2;
+ resolveRun(card, index);
+ }
+ }
+ return undefined;
+ }
+
+ hand.addEventListener('click', ev => {
+ let card;
+ if (ev.target.classList.contains('jest-card-hitslop')) {
+ card = ev.target.firstChild;
+ } else if (ev.target.classList.contains('jest-card')) {
+ card = ev.target;
+ } else if (ev.target.classList.contains('jest-card-front')) {
+ card = ev.target.parentElement;
+ }
+ if (card) {
+ const index = parseInt(card.dataset.index, 10);
+ runTest(card, index);
+ }
+ });
+
+ let resizeTimeout;
+
+ window.addEventListener('resize', () => {
+ if (!resizeTimeout) {
+ resizeTimeout = setTimeout(() => {
+ resizeTimeout = null;
+ positionCards();
+ }, 500);
+ }
+ });
+
+ function setUpMatcherButtons() {
+ const matcherSection = document.querySelector('.matchers .blockContent');
+ const screenshotImg = document.querySelector('.matchers img');
+ const buttonWrapper = document.createElement('p');
+ buttonWrapper.className = 'buttons-wrapper';
+
+ const buttons = [
+ {
+ title: 'Equals',
+ url: '/img/content/matchers/equals.png',
+ },
+ {
+ title: 'Mocks',
+ url: '/img/content/matchers/mocks.png',
+ },
+ {
+ title: 'Types',
+ url: '/img/content/matchers/different-types.png',
+ },
+ {
+ title: 'Properties',
+ url: '/img/content/matchers/missing-properties.png',
+ },
+ {
+ title: 'Snapshots',
+ url: '/img/content/matchers/snapshot.png',
+ },
+ {
+ title: 'Inline Snapshots',
+ url: '/img/content/matchers/inline-snapshot.png',
+ },
+ {
+ title: 'Functions',
+ url: '/img/content/matchers/functions.png',
+ },
+ ];
+
+ screenshotImg.onload = () => {
+ screenshotImg.style.opacity = 1;
+ };
+
+ for (const button of buttons) {
+ const clickButton = document.createElement('a');
+ clickButton.text = button.title;
+ clickButton.className = 'button landing';
+ clickButton.onclick = () => {
+ document
+ .querySelectorAll('.matchers .button.landing')
+ .forEach(b => (b.className = 'button landing'));
+ clickButton.className = 'button landing active';
+ screenshotImg.style.opacity = 0.5;
+ screenshotImg.src = button.url;
+ };
+ buttonWrapper.appendChild(clickButton);
+ }
+
+ matcherSection.appendChild(buttonWrapper);
+
+ const firstButton = document.querySelector(
+ '.matchers .blockContent .button'
+ );
+ firstButton.onclick();
+ }
+
+ // Without forking Docusaurus which is on route to a breaking major semver,
+ // we can't make the screenshots clickable. This fixes that with client-side
+ // JS. Let's call it progressive enhancement, sure.
+ function makeScreenshotsClickable() {
+ document.querySelectorAll('.blockImage img').forEach(img => {
+ console.log('-');
+ img.style.cursor = 'pointer';
+ img.onclick = () => {
+ document.location = img.src;
+ };
+ });
+ }
+
+ forceRun(2000);
+ positionCards();
+ setUpMatcherButtons();
+ makeScreenshotsClickable();
+});