Skip to content

Commit

Permalink
Merge pull request #1879 from holium/testing-strategy
Browse files Browse the repository at this point in the history
hosting.holium.com: Automated E2E test
  • Loading branch information
gdbroman authored Jul 9, 2023
2 parents e15ccfc + de03454 commit 755ace3
Show file tree
Hide file tree
Showing 27 changed files with 905 additions and 57 deletions.
7 changes: 7 additions & 0 deletions .docs/TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Holium Testing Strategy

## holium.hosting.com

The hosting website (hosting.holium.com) involves Stripe payments and is thus tested E2E with Cypress.

The Realm client itself is changed at a fast pace, so automated testing is not worth the cost at the time of writing.
29 changes: 29 additions & 0 deletions .github/workflows/cypress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Cypress Tests
on:
pull_request:
paths:
- 'hosting-holium-com/**/*.js'
- 'hosting-holium-com/**/*.ts'
- 'hosting-holium-com/**/*.tsx'
- 'hosting-holium-com/**/*.jsx'

env:
NODE_ENV: development
API_URL: 'https://backend-server-test.thirdearth.com'
API_HEADERS_VERSION: '2'
API_HEADERS_CLIENT_ID: '5'
STRIPE_KEY: 'pk_test_51LIclKGa9esKD8bTeH2WlTZ8ZyJiwXfc5M6e1RdV01zH8G5x3kq0EZbN9Zuhtkm6WBXslp6MQlErpP8lkKtwSMqf00NomWTPxM'
AMPLITUDE_API_KEY: '03a37e80acd72a1db6d8212a164db540'
CONVERTKIT_API_KEY: ''

jobs:
cypress-run:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cypress run
uses: cypress-io/github-action@v5
with:
build: yarn workspace @holium/hosting-holium-com build
start: yarn workspace @holium/hosting-holium-com start
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,7 @@ urbit/*

# Vercel
.vercel

# Cypress local videos and screenshots
**/cypress/videos
**/cypress/screenshots
12 changes: 12 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from 'cypress';

export default defineConfig({
env: {
API_URL: 'https://backend-server-test.thirdearth.com',
},
e2e: {
experimentalStudio: true,
},
// Disable chromeWebSecurity to allow Stripe Elements to work
chromeWebSecurity: false,
});
177 changes: 177 additions & 0 deletions cypress/e2e/purchase-id.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { ChooseIdServerSideProps } from '../../hosting-holium-com/src/pages/choose-id';
import getUserShipsFixture from '../fixtures/get-user-ships.json';
import provisionalShipEntryFixture from '../fixtures/provisional-ship-entry.json';
import raiseAlarmFixture from '../fixtures/raise-alarm.json';
import refreshTokenFixture from '../fixtures/refresh-token.json';
import registerFixture from '../fixtures/register.json';
import stripeMakePaymentFixture from '../fixtures/stripe-make-payment.json';
import verifyAccountFixture from '../fixtures/verify-account.json';

import 'cypress-plugin-stripe-elements';

const API_BASE_URL = Cypress.env('API_URL');

describe('hosting.holium.com', () => {
beforeEach(() => {
// Always intercept /refresh-token
cy.intercept('GET', `${API_BASE_URL}/refresh-token`, {
statusCode: 200,
body: refreshTokenFixture,
}).as('refreshToken');

// We can't intercept GET '/products/en' and '/operator/get-planets-to-sell/*
// since they're server-side. But we can stub the client page request and alter the response
cy.intercept('GET', '**/choose-id.json', (req) => {
req.reply((res) => {
const mockedPageProps: ChooseIdServerSideProps = {
identities: ['~dislet-polfed', '~lopbud-forfyl'],
back_url: '',
};
res.body.pageProps = mockedPageProps;
});
}).as('getProducts');

// Intercept Stripe API calls
cy.intercept('GET', 'https://js.stripe.com/v3/.deploy_status_henson.json', {
statusCode: 200,
body: {},
}).as('stripeJs');
cy.intercept('GET', 'https://js.stripe.com/v3/fingerprinted/data/*', {
statusCode: 200,
body: {},
}).as('stripeJs');
cy.intercept(
'GET',
'https://merchant-ui-api.stripe.com/elements/sessions*',
{
statusCode: 200,
body: {},
}
).as('stripeElements');
cy.intercept('GET', 'https://api.stripe.com/v1/elements/sessions*', {
statusCode: 200,
body: {},
}).as('stripeElements');
cy.intercept('POST', 'https://r.stripe.com/0', {
statusCode: 200,
body: {},
}).as('stripeJs-0');
cy.intercept('POST', 'https://r.stripe.com/6', {
statusCode: 200,
body: {},
}).as('stripeJs-6');
cy.intercept('POST', 'https://api.stripe.com/v1/payment_methods', {
statusCode: 200,
body: {},
}).as('createPaymentMethod');
cy.intercept(
'POST',
'https://api.stripe.com/v1/payment_intents/*/confirm',
{
body: {
// stripe client requires `error` to be present for both success and failed response
error: false,
status: 'succeeded',
},
}
).as('confirmPayment');
cy.intercept('POST', 'https://m.stripe.com/6', {
statusCode: 200,
body: {},
}).as('stripeJs-6');
});

it("executes the full 'Purchase ID' flow", () => {
cy.visit('http://localhost:3000');

/* --- PURCHASE ID / UPLOAD ID STEP --- */
cy.get('button').contains('Purchase ID').click();
// Fill in email input with 'test@localhost.com'
cy.get('input[type="email"]').type('test@localhost.com');
// Fill in password and confirm password inputs with 'password'
cy.get('input[type="password"]').each(($el) => {
cy.wrap($el).type('password');
});
// Intercept the API response
cy.intercept('POST', `${API_BASE_URL}/register`, {
statusCode: 200,
body: registerFixture,
}).as('register');
// Click button with text 'Next'
cy.get('button').contains('Next').click();

/* --- VERIFY EMAIL STEP --- */
cy.contains('Verify email');
// Fill in 'xyzw' in the text input
cy.get('input[type="text"]').type('xyzw');
// Intercept the API response
cy.intercept('POST', `${API_BASE_URL}/verify-account`, {
statusCode: 200,
body: verifyAccountFixture,
}).as('verifyAccount');

/* --- SELECT PLANET STEP --- */
cy.get('button').contains('Next').click();
// Click div with text '~lopbud-forfyl'
cy.get('div').contains('~lopbud-forfyl').click();

/* --- PAYMENT STEP --- */
cy.get('button').contains('Next').click();
// Intercept POST '/stripe-make-payment'
cy.intercept('POST', `${API_BASE_URL}/stripe-make-payment`, {
statusCode: 200,
body: stripeMakePaymentFixture,
}).as('stripeMakePayment');
// Intercept POST /user/raise-alarm
cy.intercept('POST', `${API_BASE_URL}/user/raise-alarm`, {
statusCode: 200,
body: raiseAlarmFixture,
}).as('raiseAlarm');
// Intercept PUT /update-payment-status
cy.intercept('PUT', `${API_BASE_URL}/update-payment-status`, {
statusCode: 200,
body: {},
}).as('updatePaymentStatus');
// Intercept PUT /update-planet-status
cy.intercept('PUT', `${API_BASE_URL}/update-planet-status`, {
statusCode: 200,
body: {},
}).as('updatePlanetStatus');
// Intercept POST /provisional-ship-entry
cy.intercept('POST', `${API_BASE_URL}/provisional-ship-entry`, {
statusCode: 200,
body: provisionalShipEntryFixture,
}).as('provisionalShipEntry');

// Fill card number input with '4242424242424242'
cy.fillElementsInput('cardNumber', '4242424242424242');
// Fill expiry date input with '12/24'
cy.fillElementsInput('cardExpiry', '12/24');
// Fill CVC input with '123'
cy.fillElementsInput('cardCvc', '123');
// Click button with text 'Submit'
cy.get('button').contains('Submit').click();

/* --- BOOTING STEP --- */
// Intercept first GET /get-user-ships, then click button with text 'Next'
cy.intercept('GET', `${API_BASE_URL}/get-user-ships`, {
statusCode: 200,
body: getUserShipsFixture,
}).as('getUserShips');

// Wait until GET /get-user-ships is called
cy.wait('@getUserShips', { timeout: 10000 });
// Wait until Next button is enabled and click it
cy.get('button').contains('Next').should('not.be.disabled').click();

/* --- CREDENTIALS STEP --- */
cy.contains('Credentials');
cy.contains('Save this information');
cy.contains('~lopbud-forfyl');
cy.get('button').contains('Next').should('not.be.disabled').click();

/* --- DOWNLOAD STEP --- */
cy.contains('Download Realm for desktop');
cy.get('button').contains('Go to account').should('not.be.disabled');
});
});
35 changes: 35 additions & 0 deletions cypress/fixtures/get-user-ships.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[
{
"subscription_id": "sub_1NRwVqGa9esKD8bTt5tptZKT",
"transaction_id": 1915,
"email": "forkuzasti@gufum.com",
"payment_status": "OK",
"subscription_price": 13,
"id": 1463,
"patp": "~lopbud-forfyl",
"ship_type": "planet",
"sponsor": "botwet",
"screen_name": "dislet-polfed",
"sigil": null,
"code": "tonlur-sanhus-natfyn-hobnup",
"link": "https://dislet-polfed.plymouth.network",
"ames_port": "",
"tcp_port": "8082",
"first_boot": false,
"ship_status": "active",
"user_id": 759,
"droplet_id": 389,
"created_at": "2023-07-09T12:15:31.061Z",
"updated_at": "2023-07-09T12:16:03.341Z",
"eth_address": null,
"last_restarted": "2023-07-09T12:15:31.061Z",
"product_id": 30,
"invoice_id": "in_1NRwVqGa9esKD8bTHUQ0KYQi",
"maintenance_window": 7,
"droplet_ip": "159.223.147.108",
"title": "Realm Planet",
"description": "Billed monthly. Testing Holium configuration and installs on the livenet",
"is_migration": false,
"product_type": "planet"
}
]
110 changes: 110 additions & 0 deletions cypress/fixtures/products.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
[
{
"id": 30,
"priority": 3,
"title": "Realm Planet",
"description": "Billed monthly. Testing Holium configuration and installs on the livenet",
"long_description": "There would ususally be a long description here explaining what you were getting into, how it was priced, etc.",
"lang_code": "en",
"client_id": 5,
"is_migration": false,
"subscription_price": 13,
"price_id": "price_1MgbQvGa9esKD8bT1y4Xb6XP",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "planet"
},
{
"id": 32,
"priority": 4,
"title": "Realm Planet",
"description": "Billed annually. Testing Holium configuration and installs on the livenet",
"long_description": "There would ususally be a long description here explaining what you were getting into, how it was priced, etc.",
"lang_code": "en",
"client_id": 5,
"is_migration": false,
"subscription_price": 130,
"price_id": "price_1Mr1glGa9esKD8bTIUKVUfQU",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "planet"
},
{
"id": 100,
"priority": 15,
"title": "BYOP (Name & Key)",
"description": "Bring Your Own Planet. If you already own a planet with either an unused network key or a factory reset network key, why not enjoy the convenience of hosting your Identity in Holium's reliable environment?",
"long_description": "No minimum contract. <strong>NOTE: Not for currently running ships unless you are planning to factory reset them in <a href='https://bridge.urbit.org' target='__blank'>Bridge</a>.</strong> If you want to move your existing ship with all of its apps, subscriptions, and configurations to ThirdEarth, purchase our <strong>BYOP (Pier)</strong> product instead.<br /><br />Requires: Your planet's name and its network key, found in the keyfile obtained from <a href='https://bridge.urbit.org' target='__blank'>Bridge</a>. This key must be unused, i.e., you must not have launched this planet before using this key, or you must have factory reset your planet to obtain a new unused key.<br /><br />Included: 5GB of ID data storage, 2GB of S3 data storage, and 200GB/month sent data allowance. Starting in 2023, overage charges will begin to be assessed: Each 0-5GB used over the allowance for ID data or S3 data = $1/month. Each 0-100GB of data sent over the combined allowance per calendar month = $1.",
"lang_code": "en",
"client_id": 5,
"is_migration": null,
"subscription_price": 12,
"price_id": "price_1NGNluGa9esKD8bT95MoE6QH",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "byop-nk"
},
{
"id": 101,
"priority": 15,
"title": "BYOP (Pier)",
"description": "Bring Your Own Planet. If you already own a planet that you would like to migrate to a convenient and reliable hosting environment, BYOP (Pier) is the choice for you, providing consistent availability and automatic weekly maintenance.",
"long_description": "No minimum contract. This option is for people who want to move their existing ship with all of its apps, subscriptions, and configurations to ThirdEarth hosting. If you want to launch (for the first time) or re-launch a ship that you already own, purchase our <strong>BYOP (Name & Key)</strong> product.<br /><br />Requires: A compressed archive of your existing pier in .zip or .tar.gz format which was created after the ship was shut down at its current location permanently.<br /><br />Included: 5GB of ID data storage, 2GB of S3 data storage, and 200GB/month sent data allowance. Starting in 2023, overage charges will begin to be assessed: Each 0-5GB used over the allowance for ID data or S3 data = $1/month. Each 0-100GB of data sent over the combined allowance per calendar month = $1.",
"lang_code": "en",
"client_id": 5,
"is_migration": true,
"subscription_price": 12,
"price_id": "price_1NGNmgGa9esKD8bTJVJI1ECj",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "byop-p"
},
{
"id": 102,
"priority": 15,
"title": "BYOP (Name & Key)",
"description": "Bring Your Own Planet. If you already own a planet with either an unused network key or a factory reset network key, why not enjoy the convenience of hosting your Identity in Holium's reliable environment?",
"long_description": "None",
"lang_code": "en",
"client_id": 5,
"is_migration": null,
"subscription_price": 120,
"price_id": "price_1NLAxTGa9esKD8bTHA1NNy7o",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "byop-nk"
},
{
"id": 103,
"priority": 15,
"title": "BYOP (Pier)",
"description": "Bring Your Own Planet. If you already own a planet that you would like to migrate to a convenient and reliable hosting environment, BYOP (Pier) is the choice for you, providing consistent availability and automatic weekly maintenance.",
"long_description": "None",
"lang_code": "en",
"client_id": 5,
"is_migration": true,
"subscription_price": 120,
"price_id": "price_1NLArWGa9esKD8bTtv4y4Uyn",
"is_planet": true,
"droplet_class_id": 2,
"product_status": "active",
"threshold": null,
"comet_count": "0",
"product_type": "byop-p"
}
]
Loading

2 comments on commit 755ace3

@vercel
Copy link

@vercel vercel bot commented on 755ace3 Jul 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

hosting-holium-com – ./hosting-holium-com

hosting-holium-com-git-master-holium.vercel.app
hosting-holium-com-holium.vercel.app
realm-onboarding.vercel.app
hosting.holium.com

@vercel
Copy link

@vercel vercel bot commented on 755ace3 Jul 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

holium-com – ./holium-com

holium-com-git-master-holium.vercel.app
holium-com-holium.vercel.app
holium.com
holium-com-blue.vercel.app
www.holium.com

Please sign in to comment.