diff --git a/app/views/shared/authentication/_email_login_form.html.erb b/app/views/shared/authentication/_email_login_form.html.erb
index 3d94ca5f0..4526d0a87 100644
--- a/app/views/shared/authentication/_email_login_form.html.erb
+++ b/app/views/shared/authentication/_email_login_form.html.erb
@@ -1,4 +1,4 @@
-<%= form_for(User.new, as: :user, url: session_path(:user)) do |f| %>
+<%= form_for(User.new, as: :user, url: session_path(:user), data: { testid: "login-form" }) do |f| %>
<%= f.label :email, class: "crayons-field__label" %>
<%= f.email_field :email, autocomplete: "email", class: "crayons-textfield" %>
diff --git a/config/webpack/environment.js b/config/webpack/environment.js
index fac1b32a2..156e7874c 100644
--- a/config/webpack/environment.js
+++ b/config/webpack/environment.js
@@ -24,25 +24,6 @@ environment.splitChunks((config) => {
'@utilities': path.resolve(__dirname, '../../app/javascript/utilities'),
},
},
- optimization: {
- ...config.optimization,
- splitChunks: {
- ...config.optimization.splitChunks,
- cacheGroups: {
- vendor: {
- test: /node_modules/,
- chunks: 'initial',
- name: 'vendor',
- enforce: true,
- },
- default: {
- minChunks: 2,
- priority: -20,
- reuseExistingChunk: true,
- },
- },
- },
- },
};
});
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 000000000..17ef242e7
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1,3 @@
+{
+ "baseUrl": "http://localhost:3000"
+}
diff --git a/cypress/.eslintrc.js b/cypress/.eslintrc.js
index 0a9f33ff6..6b42f8074 100644
--- a/cypress/.eslintrc.js
+++ b/cypress/.eslintrc.js
@@ -32,6 +32,7 @@ module.exports = {
},
],
env: {
+ node: true,
'cypress/globals': true,
},
};
diff --git a/cypress/fixtures/logins/initialAdmin.json b/cypress/fixtures/logins/initialAdmin.json
new file mode 100644
index 000000000..b961629f6
--- /dev/null
+++ b/cypress/fixtures/logins/initialAdmin.json
@@ -0,0 +1,4 @@
+{
+ "user": "admin@forem.local",
+ "password": "password"
+}
diff --git a/cypress/integration/loginFlows/initialAdminLogin.spec.js b/cypress/integration/loginFlows/initialAdminLogin.spec.js
new file mode 100644
index 000000000..3f039d7a0
--- /dev/null
+++ b/cypress/integration/loginFlows/initialAdminLogin.spec.js
@@ -0,0 +1,30 @@
+describe('First time for first administrator login', () => {
+ // Note if you are running these tests locallly, this test will fail
+ // if the first admin has already gone through the onboarding process.
+ it('should login the initial administrator user from the home page', () => {
+ cy.fixture('logins/initialAdmin.json').as('admin');
+
+ // Go to home page
+ cy.visit('/');
+
+ // Click on the login button in the top header
+ cy.findAllByText('Log in').first().click();
+
+ // Ensure we are redirected to the login page
+ cy.url().should('contains', '/enter');
+
+ cy.findByTestId('login-form').as('loginForm');
+ cy.get('@admin').then((admin) => {
+ // Enter credentials for the initial administrator user
+ cy.get('@loginForm').findByText('Email').type(admin.user);
+ cy.get('@loginForm').findByText('Password').type(admin.password);
+ });
+
+ // Submit the form
+ cy.get('@loginForm').findByText('Continue').click();
+
+ // User should be redirected to onboarding
+ const { baseUrl } = Cypress.config();
+ cy.url().should('include', `/onboarding?referrer=${baseUrl}/?signin=true`);
+ });
+});
diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js
new file mode 100644
index 000000000..3596c1897
--- /dev/null
+++ b/cypress/plugins/index.js
@@ -0,0 +1,21 @@
+///
+// ***********************************************************
+// This example plugins/index.js can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+/**
+ * @type {Cypress.PluginConfig}
+ */
+module.exports = (_on, _config) => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+};
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 000000000..ca4d256f3
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,25 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add("login", (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
diff --git a/cypress/support/index.js b/cypress/support/index.js
new file mode 100644
index 000000000..285ea3738
--- /dev/null
+++ b/cypress/support/index.js
@@ -0,0 +1,23 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// For Testing Library APIs https://github.com/testing-library/cypress-testing-library
+import '@testing-library/cypress/add-commands';
+
+// Import commands.js using ES2015 syntax:
+import './commands';
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/package.json b/package.json
index 0af226988..73cc7ab7a 100644
--- a/package.json
+++ b/package.json
@@ -96,6 +96,7 @@
"@storybook/addon-storysource": "^6.1.10",
"@storybook/addons": "^6.1.5",
"@storybook/preact": "^6.1.9",
+ "@testing-library/cypress": "^7.0.2",
"@testing-library/dom": "^7.28.1",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/preact": "^2.0.1",
diff --git a/yarn.lock b/yarn.lock
index 925f473f6..d85697671 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3065,7 +3065,15 @@
dependencies:
defer-to-connect "^1.0.1"
-"@testing-library/dom@^7.16.2", "@testing-library/dom@^7.28.1":
+"@testing-library/cypress@^7.0.2":
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/@testing-library/cypress/-/cypress-7.0.2.tgz#a97bc7dee8756aff195e5be57db2889fe292f923"
+ integrity sha512-avBCbcCMPFHvWg4BBCA/pIh3MCwcKoJ+rc3XyZdKC5mFYPV7edjW3s4KZx/x3klXuttyuM/UesRhbSj4l5aQbw==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@testing-library/dom" "^7.26.6"
+
+"@testing-library/dom@^7.16.2", "@testing-library/dom@^7.26.6", "@testing-library/dom@^7.28.1":
version "7.28.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.28.1.tgz#dea78be6e1e6db32ddcb29a449e94d9700c79eb9"
integrity sha512-acv3l6kDwZkQif/YqJjstT3ks5aaI33uxGNVIQmdKzbZ2eMKgg3EV2tB84GDdc72k3Kjhl6mO8yUt6StVIdRDg==