Merge branch 'feat-cypress' into 'master'
feat: Add cypress for integration testing See merge request mythic-insight/legendary!104
This commit is contained in:
		
						commit
						d3bc7ce0bb
					
				
					 38 changed files with 3249 additions and 135 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -47,3 +47,7 @@ build.env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CI metrics file
 | 
					# CI metrics file
 | 
				
			||||||
metrics.txt
 | 
					metrics.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cypress Artifacts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/apps/*/cypress/videos/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,9 @@ variables:
 | 
				
			||||||
  # fetch & clean the repo rather than completely cloning (faster)
 | 
					  # fetch & clean the repo rather than completely cloning (faster)
 | 
				
			||||||
  GIT_STRATEGY: fetch
 | 
					  GIT_STRATEGY: fetch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include:
 | 
				
			||||||
 | 
					- .gitlab/ci/.cypress.yml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test stage. Runs various tests and speculatively builds docker image in
 | 
					# Test stage. Runs various tests and speculatively builds docker image in
 | 
				
			||||||
#   parallel, in case the build passes.
 | 
					#   parallel, in case the build passes.
 | 
				
			||||||
.test_template: &test_template
 | 
					.test_template: &test_template
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								.gitlab/ci/.cypress.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.gitlab/ci/.cypress.yml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					cypress:
 | 
				
			||||||
 | 
					  stage: test
 | 
				
			||||||
 | 
					  image: cypress/browsers:node14.17.0-chrome91-ff89
 | 
				
			||||||
 | 
					  variables:
 | 
				
			||||||
 | 
					    MIX_ENV: e2e
 | 
				
			||||||
 | 
					  cache:
 | 
				
			||||||
 | 
					    key: $CI_JOB_NAME
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - _build/
 | 
				
			||||||
 | 
					      - deps/
 | 
				
			||||||
 | 
					      - node_modules/
 | 
				
			||||||
 | 
					      - .npm/
 | 
				
			||||||
 | 
					  artifacts:
 | 
				
			||||||
 | 
					    when: always
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - apps/*/cypress/videos/**/*.mp4
 | 
				
			||||||
 | 
					      - apps/*/cypress/screenshots/**/*.png
 | 
				
			||||||
 | 
					    expire_in: 1 day
 | 
				
			||||||
 | 
					  services:
 | 
				
			||||||
 | 
					  - name: postgres:12
 | 
				
			||||||
 | 
					  before_script:
 | 
				
			||||||
 | 
					    - script/cypress/prepare
 | 
				
			||||||
 | 
					  script:
 | 
				
			||||||
 | 
					    - npm run test:integration
 | 
				
			||||||
							
								
								
									
										3
									
								
								apps/admin/cypress.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/admin/cypress.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "baseUrl": "http://localhost:4002"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								apps/admin/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/admin/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					describe('My First Test', () => {
 | 
				
			||||||
 | 
					  it('Does not do much!', () => {
 | 
				
			||||||
 | 
					    expect(true).to.equal(true)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										22
									
								
								apps/admin/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/admin/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					/// <reference types="cypress" />
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line no-unused-vars
 | 
				
			||||||
 | 
					module.exports = (on, config) => {
 | 
				
			||||||
 | 
					  // `on` is used to hook into various events Cypress emits
 | 
				
			||||||
 | 
					  // `config` is the resolved Cypress config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/admin/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/admin/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					// ***********************************************
 | 
				
			||||||
 | 
					// 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) => { ... })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("setupDB", (app, seedSet) => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/setup', {
 | 
				
			||||||
 | 
					    app,
 | 
				
			||||||
 | 
					    seed_set: seedSet,
 | 
				
			||||||
 | 
					  }).as('setupDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("teardownDB", () => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/teardown').as('teardownDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										29
									
								
								apps/admin/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								apps/admin/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Import commands.js using ES2015 syntax:
 | 
				
			||||||
 | 
					import './commands'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Alternatively you can use CommonJS syntax:
 | 
				
			||||||
 | 
					// require('./commands')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					before(() => {
 | 
				
			||||||
 | 
					  // Make sure we don't have a rogue DB connection checked out
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					afterEach(() => {
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/admin/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/admin/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								apps/app/cypress.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/app/cypress.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "baseUrl": "http://localhost:4002"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								apps/app/cypress/fixtures/example.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/app/cypress/fixtures/example.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "Using fixtures to represent data",
 | 
				
			||||||
 | 
					  "email": "hello@cypress.io",
 | 
				
			||||||
 | 
					  "body": "Fixtures are a great way to mock data for responses to routes"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								apps/app/cypress/integration/blog_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apps/app/cypress/integration/blog_spec.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					describe('Blog Page', () => {
 | 
				
			||||||
 | 
					  it('shows posts', () => {
 | 
				
			||||||
 | 
					    cy.setupDB("app", "blog")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cy.visit('/blog')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cy.get('article').should('exist')
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										22
									
								
								apps/app/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/app/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					/// <reference types="cypress" />
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line no-unused-vars
 | 
				
			||||||
 | 
					module.exports = (on, config) => {
 | 
				
			||||||
 | 
					  // `on` is used to hook into various events Cypress emits
 | 
				
			||||||
 | 
					  // `config` is the resolved Cypress config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/app/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/app/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					// ***********************************************
 | 
				
			||||||
 | 
					// 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) => { ... })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("setupDB", (app, seedSet) => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/setup', {
 | 
				
			||||||
 | 
					    app,
 | 
				
			||||||
 | 
					    seed_set: seedSet,
 | 
				
			||||||
 | 
					  }).as('setupDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("teardownDB", () => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/teardown').as('teardownDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										29
									
								
								apps/app/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								apps/app/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Import commands.js using ES2015 syntax:
 | 
				
			||||||
 | 
					import './commands'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Alternatively you can use CommonJS syntax:
 | 
				
			||||||
 | 
					// require('./commands')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					before(() => {
 | 
				
			||||||
 | 
					  // Make sure we don't have a rogue DB connection checked out
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					afterEach(() => {
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					@ -51,6 +51,10 @@ defmodule AppWeb.Router do
 | 
				
			||||||
    forward "/sent_emails", Bamboo.SentEmailViewerPlug
 | 
					    forward "/sent_emails", Bamboo.SentEmailViewerPlug
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if Mix.env() == :e2e do
 | 
				
			||||||
 | 
					    forward("/end-to-end", Legendary.CoreWeb.Plug.TestEndToEnd, otp_app: :app)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  scope "/" do
 | 
					  scope "/" do
 | 
				
			||||||
    pipe_through :browser
 | 
					    pipe_through :browser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ defmodule App.MixProject do
 | 
				
			||||||
      {:admin, in_umbrella: true},
 | 
					      {:admin, in_umbrella: true},
 | 
				
			||||||
      {:content, in_umbrella: true},
 | 
					      {:content, in_umbrella: true},
 | 
				
			||||||
      {:core, in_umbrella: true},
 | 
					      {:core, in_umbrella: true},
 | 
				
			||||||
      {:ecto_sql, "~> 3.4"},
 | 
					      {:ecto_sql, "~> 3.6"},
 | 
				
			||||||
      {:excoveralls, "~> 0.10", only: [:dev, :test]},
 | 
					      {:excoveralls, "~> 0.10", only: [:dev, :test]},
 | 
				
			||||||
      {:floki, ">= 0.30.0"},
 | 
					      {:floki, ">= 0.30.0"},
 | 
				
			||||||
      {:oban, "~> 2.1"},
 | 
					      {:oban, "~> 2.1"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								apps/app/test/seed_sets/blog.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								apps/app/test/seed_sets/blog.exs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					alias Legendary.Content.Post
 | 
				
			||||||
 | 
					alias Legendary.Content.Repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%Post{
 | 
				
			||||||
 | 
					  title: "Public post",
 | 
				
			||||||
 | 
					  name: "public-post",
 | 
				
			||||||
 | 
					  status: "publish",
 | 
				
			||||||
 | 
					  type: "post",
 | 
				
			||||||
 | 
					  date: ~N[2020-01-01T00:00:00],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					|> Repo.insert!()
 | 
				
			||||||
							
								
								
									
										3
									
								
								apps/content/cypress.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/content/cypress.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "baseUrl": "http://localhost:4002"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								apps/content/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/content/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					describe('My First Test', () => {
 | 
				
			||||||
 | 
					  it('Does not do much!', () => {
 | 
				
			||||||
 | 
					    expect(true).to.equal(true)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										22
									
								
								apps/content/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/content/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					/// <reference types="cypress" />
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line no-unused-vars
 | 
				
			||||||
 | 
					module.exports = (on, config) => {
 | 
				
			||||||
 | 
					  // `on` is used to hook into various events Cypress emits
 | 
				
			||||||
 | 
					  // `config` is the resolved Cypress config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/content/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/content/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					// ***********************************************
 | 
				
			||||||
 | 
					// 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) => { ... })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("setupDB", (app, seedSet) => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/setup', {
 | 
				
			||||||
 | 
					    app,
 | 
				
			||||||
 | 
					    seed_set: seedSet,
 | 
				
			||||||
 | 
					  }).as('setupDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("teardownDB", () => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/teardown').as('teardownDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										29
									
								
								apps/content/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								apps/content/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Import commands.js using ES2015 syntax:
 | 
				
			||||||
 | 
					import './commands'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Alternatively you can use CommonJS syntax:
 | 
				
			||||||
 | 
					// require('./commands')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					before(() => {
 | 
				
			||||||
 | 
					  // Make sure we don't have a rogue DB connection checked out
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					afterEach(() => {
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,8 @@ defmodule Legendary.Content.MixProject do
 | 
				
			||||||
      {:neotomex, "~> 0.1.7"},
 | 
					      {:neotomex, "~> 0.1.7"},
 | 
				
			||||||
      {:oban, "~> 2.1"},
 | 
					      {:oban, "~> 2.1"},
 | 
				
			||||||
      {:phoenix, "~> 1.5.8"},
 | 
					      {:phoenix, "~> 1.5.8"},
 | 
				
			||||||
      {:phoenix_ecto, "~> 4.0"},
 | 
					      {:phoenix_ecto, "~> 4.1"},
 | 
				
			||||||
 | 
					      {:ecto_sql, "~> 3.6"},
 | 
				
			||||||
      {:phoenix_html, "~> 2.11"},
 | 
					      {:phoenix_html, "~> 2.11"},
 | 
				
			||||||
      {:phoenix_html_sanitizer, "~> 1.1.0"},
 | 
					      {:phoenix_html_sanitizer, "~> 1.1.0"},
 | 
				
			||||||
      {:phoenix_live_reload, "~> 1.2", only: :dev},
 | 
					      {:phoenix_live_reload, "~> 1.2", only: :dev},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/content/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/content/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								apps/core/cypress.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/core/cypress.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "baseUrl": "http://localhost:4002"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								apps/core/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/core/cypress/integration/example_spec.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					describe('My First Test', () => {
 | 
				
			||||||
 | 
					  it('Does not do much!', () => {
 | 
				
			||||||
 | 
					    expect(true).to.equal(true)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										22
									
								
								apps/core/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/core/cypress/plugins/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					/// <reference types="cypress" />
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line no-unused-vars
 | 
				
			||||||
 | 
					module.exports = (on, config) => {
 | 
				
			||||||
 | 
					  // `on` is used to hook into various events Cypress emits
 | 
				
			||||||
 | 
					  // `config` is the resolved Cypress config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								apps/core/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/core/cypress/support/commands.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					// ***********************************************
 | 
				
			||||||
 | 
					// 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) => { ... })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("setupDB", (app, seedSet) => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/setup', {
 | 
				
			||||||
 | 
					    app,
 | 
				
			||||||
 | 
					    seed_set: seedSet,
 | 
				
			||||||
 | 
					  }).as('setupDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cypress.Commands.add("teardownDB", () => {
 | 
				
			||||||
 | 
					  cy.request('POST', '/end-to-end/db/teardown').as('teardownDB')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										29
									
								
								apps/core/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								apps/core/cypress/support/index.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					// ***********************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Import commands.js using ES2015 syntax:
 | 
				
			||||||
 | 
					import './commands'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Alternatively you can use CommonJS syntax:
 | 
				
			||||||
 | 
					// require('./commands')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					before(() => {
 | 
				
			||||||
 | 
					  // Make sure we don't have a rogue DB connection checked out
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					afterEach(() => {
 | 
				
			||||||
 | 
					  cy.teardownDB()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										77
									
								
								apps/core/lib/core_web/plugs/test_end_to_end.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								apps/core/lib/core_web/plugs/test_end_to_end.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					defmodule Legendary.CoreWeb.Plug.TestEndToEnd do
 | 
				
			||||||
 | 
					  @moduledoc """
 | 
				
			||||||
 | 
					  Provides an API used by Cypress to remote control the database state for
 | 
				
			||||||
 | 
					  integration tests.
 | 
				
			||||||
 | 
					  """
 | 
				
			||||||
 | 
					  use Plug.Router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  plug :match
 | 
				
			||||||
 | 
					  plug :dispatch, builder_opts()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  post "/db/setup" do
 | 
				
			||||||
 | 
					    # If the agent is registered and alive, a db connection is checked out already
 | 
				
			||||||
 | 
					    # Otherwise, we spawn the agent and let it(!) check out the db connection
 | 
				
			||||||
 | 
					    owner_process = Process.whereis(:db_owner_agent)
 | 
				
			||||||
 | 
					    if owner_process && Process.alive?(owner_process) do
 | 
				
			||||||
 | 
					      send_resp(conn, 200, "connection has already been checked out")
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      {:ok, _pid} = Agent.start_link(&checkout_shared_db_conn/0, name: :db_owner_agent)
 | 
				
			||||||
 | 
					      {:ok, _} = load_test_seeds(conn)
 | 
				
			||||||
 | 
					      send_resp(conn, 200, "connection checked out")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  post "/db/teardown" do
 | 
				
			||||||
 | 
					    # If the agent is registered and alive, we check the connection back in
 | 
				
			||||||
 | 
					    # Otherwise, no connection has been checked out, we ignore this
 | 
				
			||||||
 | 
					    owner_process = Process.whereis(:db_owner_agent)
 | 
				
			||||||
 | 
					    if owner_process && Process.alive?(owner_process) do
 | 
				
			||||||
 | 
					      Agent.get(owner_process, &checkin_shared_db_conn/1)
 | 
				
			||||||
 | 
					      Agent.stop(owner_process)
 | 
				
			||||||
 | 
					      send_resp(conn, 200, "checked in database connection")
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      send_resp(conn, 200, "connection has already been checked back in")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  match _, do: send_resp(conn, 404, "Not found")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp checkout_shared_db_conn do
 | 
				
			||||||
 | 
					    Ecto.Repo.all_running()
 | 
				
			||||||
 | 
					    |> Enum.map(fn repo ->
 | 
				
			||||||
 | 
					      :ok = Ecto.Adapters.SQL.Sandbox.checkout(repo, ownership_timeout: :infinity)
 | 
				
			||||||
 | 
					      :ok = Ecto.Adapters.SQL.Sandbox.mode(repo, {:shared, self()})
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp checkin_shared_db_conn(_) do
 | 
				
			||||||
 | 
					    Ecto.Repo.all_running()
 | 
				
			||||||
 | 
					    |> Enum.map(fn repo ->
 | 
				
			||||||
 | 
					      :ok = Ecto.Adapters.SQL.Sandbox.checkin(repo)
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @valid_seed_set_characters ~r{\A[A-Za-z\-_/]+\z}
 | 
				
			||||||
 | 
					  @valid_app_characters ~r{\A[a-z_]+\z}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp load_test_seeds(conn) do
 | 
				
			||||||
 | 
					    with {:ok, seed_set} <- Map.fetch(conn.body_params, "seed_set"),
 | 
				
			||||||
 | 
					         {:app, {:ok, app}} <- {:app, Map.fetch(conn.body_params, "app")},
 | 
				
			||||||
 | 
					         true <- String.match?(seed_set, @valid_seed_set_characters),
 | 
				
			||||||
 | 
					         true <- String.match?(app, @valid_app_characters) do
 | 
				
			||||||
 | 
					        seed_path = "apps/#{app}/test/seed_sets/#{seed_set}.exs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try do
 | 
				
			||||||
 | 
					          {result, _} = Code.eval_file(seed_path)
 | 
				
			||||||
 | 
					          {:ok, result}
 | 
				
			||||||
 | 
					        rescue
 | 
				
			||||||
 | 
					          e in Code.LoadError ->
 | 
				
			||||||
 | 
					            {:error, "could not load a seed set at #{seed_path}: #{e}"}
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      {:app, :error} -> {:error, "app parameter is required if seed set is set"}
 | 
				
			||||||
 | 
					      :error -> {:ok, nil} # seed_set param is missing
 | 
				
			||||||
 | 
					      false -> {:error, "invalid seed set name"}
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -146,7 +146,7 @@ defmodule Legendary.Core.MixProject do
 | 
				
			||||||
      {:fun_with_flags_ui, "~> 0.7.2"},
 | 
					      {:fun_with_flags_ui, "~> 0.7.2"},
 | 
				
			||||||
      {:phoenix, "~> 1.5.8"},
 | 
					      {:phoenix, "~> 1.5.8"},
 | 
				
			||||||
      {:phoenix_ecto, "~> 4.1"},
 | 
					      {:phoenix_ecto, "~> 4.1"},
 | 
				
			||||||
      {:ecto_sql, "~> 3.4"},
 | 
					      {:ecto_sql, "~> 3.6"},
 | 
				
			||||||
      {:ex_prompt, "~> 0.2.0"},
 | 
					      {:ex_prompt, "~> 0.2.0"},
 | 
				
			||||||
      {:linguist, git: "https://github.com/change/linguist.git", ref: "d67b60fd597bfe894c69773efd05ad690dad8663"},
 | 
					      {:linguist, git: "https://github.com/change/linguist.git", ref: "d67b60fd597bfe894c69773efd05ad690dad8663"},
 | 
				
			||||||
      {:postgrex, ">= 0.0.0"},
 | 
					      {:postgrex, ">= 0.0.0"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								apps/core/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								apps/core/test/seed_sets/.keep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										19
									
								
								config/e2e.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								config/e2e.exs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					use Mix.Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Start with test config
 | 
				
			||||||
 | 
					import_config "test.exs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config :app, AppWeb.Endpoint,
 | 
				
			||||||
 | 
					    http: [port: 4002],
 | 
				
			||||||
 | 
					    server: true,
 | 
				
			||||||
 | 
					    watchers: [
 | 
				
			||||||
 | 
					        node: [
 | 
				
			||||||
 | 
					          "node_modules/webpack/bin/webpack.js",
 | 
				
			||||||
 | 
					          "--mode",
 | 
				
			||||||
 | 
					          "development",
 | 
				
			||||||
 | 
					          "--watch",
 | 
				
			||||||
 | 
					          "--watch-options-stdin",
 | 
				
			||||||
 | 
					          "--progress",
 | 
				
			||||||
 | 
					          cd: Path.expand("../apps/app/assets", __DIR__)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
							
								
								
									
										14
									
								
								mix.lock
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								mix.lock
									
									
									
									
									
								
							| 
						 | 
					@ -7,19 +7,19 @@
 | 
				
			||||||
  "cldr_utils": {:hex, :cldr_utils, "2.16.0", "5abd1835151e264f6f9a285ab8c7419954a45eec5ca5a356dea592faa23e80b9", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3ef5dc0fdfe566a5a4b8bda726cf760ebada69c0600affc4cb02b5e8ae7f7b47"},
 | 
					  "cldr_utils": {:hex, :cldr_utils, "2.16.0", "5abd1835151e264f6f9a285ab8c7419954a45eec5ca5a356dea592faa23e80b9", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3ef5dc0fdfe566a5a4b8bda726cf760ebada69c0600affc4cb02b5e8ae7f7b47"},
 | 
				
			||||||
  "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
 | 
					  "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
 | 
				
			||||||
  "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"},
 | 
					  "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"},
 | 
				
			||||||
  "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
 | 
					  "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
 | 
				
			||||||
  "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
 | 
					  "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
 | 
				
			||||||
  "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
 | 
					  "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
 | 
				
			||||||
  "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
 | 
					  "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
 | 
				
			||||||
  "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
 | 
					  "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
 | 
				
			||||||
  "crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"},
 | 
					  "crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"},
 | 
				
			||||||
  "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
 | 
					  "db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"},
 | 
				
			||||||
  "decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
 | 
					  "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
 | 
				
			||||||
  "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
 | 
					  "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
 | 
				
			||||||
  "earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
 | 
					  "earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
 | 
				
			||||||
  "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
 | 
					  "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
 | 
				
			||||||
  "ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
 | 
					  "ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
 | 
				
			||||||
  "ecto_sql": {:hex, :ecto_sql, "3.4.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"},
 | 
					  "ecto_sql": {:hex, :ecto_sql, "3.6.2", "9526b5f691701a5181427634c30655ac33d11e17e4069eff3ae1176c764e0ba3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.6.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ec9d7e6f742ea39b63aceaea9ac1d1773d574ea40df5a53ef8afbd9242fdb6b"},
 | 
				
			||||||
  "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
 | 
					  "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
 | 
				
			||||||
  "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
 | 
					  "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
 | 
				
			||||||
  "ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"},
 | 
					  "ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"},
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,7 @@
 | 
				
			||||||
  "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
 | 
					  "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
 | 
				
			||||||
  "oban": {:hex, :oban, "2.1.0", "034144686f7e76a102b5d67731f098d98a9e4a52b07c25ad580a01f83a7f1cf5", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6f067fa3b308ed9e0e6beb2b34277c9c4e48bf95338edabd8f4a757a26e04c2"},
 | 
					  "oban": {:hex, :oban, "2.1.0", "034144686f7e76a102b5d67731f098d98a9e4a52b07c25ad580a01f83a7f1cf5", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6f067fa3b308ed9e0e6beb2b34277c9c4e48bf95338edabd8f4a757a26e04c2"},
 | 
				
			||||||
  "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
 | 
					  "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
 | 
				
			||||||
  "phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"},
 | 
					  "phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"},
 | 
				
			||||||
  "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
 | 
					  "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
 | 
				
			||||||
  "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
 | 
					  "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
 | 
				
			||||||
  "phoenix_html_sanitizer": {:hex, :phoenix_html_sanitizer, "1.1.0", "ea9e1162217621208ba6b2951a24abe2c06b39347f65c22c31312f9f5ac0fa75", [:mix], [{:html_sanitize_ex, "~> 1.1", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "089f28f0592d58f7cf1f032b89c13e873dc73c77a2ccf3386aee976c6ff077c9"},
 | 
					  "phoenix_html_sanitizer": {:hex, :phoenix_html_sanitizer, "1.1.0", "ea9e1162217621208ba6b2951a24abe2c06b39347f65c22c31312f9f5ac0fa75", [:mix], [{:html_sanitize_ex, "~> 1.1", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "089f28f0592d58f7cf1f032b89c13e873dc73c77a2ccf3386aee976c6ff077c9"},
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,7 @@
 | 
				
			||||||
  "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"},
 | 
					  "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"},
 | 
				
			||||||
  "plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"},
 | 
					  "plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"},
 | 
				
			||||||
  "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
 | 
					  "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
 | 
				
			||||||
  "postgrex": {:hex, :postgrex, "0.15.5", "aec40306a622d459b01bff890fa42f1430dac61593b122754144ad9033a2152f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ed90c81e1525f65a2ba2279dbcebf030d6d13328daa2f8088b9661eb9143af7f"},
 | 
					  "postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"},
 | 
				
			||||||
  "pow": {:hex, :pow, "1.0.24", "d834f5ce40c9b15a810a942de6492314e0defa157b6503e63775014b165a9c10", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.3.0 and < 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "70fe212f2b9a362a73e317cb33f506dbebd5d3bbfd3f64883898e77cc29ea9e5"},
 | 
					  "pow": {:hex, :pow, "1.0.24", "d834f5ce40c9b15a810a942de6492314e0defa157b6503e63775014b165a9c10", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.3.0 and < 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "70fe212f2b9a362a73e317cb33f506dbebd5d3bbfd3f64883898e77cc29ea9e5"},
 | 
				
			||||||
  "quantum": {:hex, :quantum, "2.4.0", "f2ad4b20988f848455d35ed0e884ba0c7629a27ee86cbec6a6e0fc214b6e69cf", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: true]}], "hexpm", "a125a9e65a5af740a1198f3b05c1a736fce3942f5e0dc2901e0f9be5745bea99"},
 | 
					  "quantum": {:hex, :quantum, "2.4.0", "f2ad4b20988f848455d35ed0e884ba0c7629a27ee86cbec6a6e0fc214b6e69cf", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12 or ~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: true]}], "hexpm", "a125a9e65a5af740a1198f3b05c1a736fce3942f5e0dc2901e0f9be5745bea99"},
 | 
				
			||||||
  "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
 | 
					  "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2805
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2805
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -5,7 +5,10 @@
 | 
				
			||||||
  "description": "The Legendary Phoenix Boilerplate.",
 | 
					  "description": "The Legendary Phoenix Boilerplate.",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
					    "test": "npm run test:integration",
 | 
				
			||||||
 | 
					    "test:integration": "start-server-and-test start-server 4002 start-test",
 | 
				
			||||||
 | 
					    "start-server": "MIX_ENV=e2e mix phx.server",
 | 
				
			||||||
 | 
					    "start-test": "mix cmd npx cypress run"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
| 
						 | 
					@ -23,9 +26,11 @@
 | 
				
			||||||
    "@semantic-release/exec": "^5.0.0",
 | 
					    "@semantic-release/exec": "^5.0.0",
 | 
				
			||||||
    "@semantic-release/git": "^9.0.0",
 | 
					    "@semantic-release/git": "^9.0.0",
 | 
				
			||||||
    "@semantic-release/npm": "^7.1.3",
 | 
					    "@semantic-release/npm": "^7.1.3",
 | 
				
			||||||
 | 
					    "cypress": "^8.2.0",
 | 
				
			||||||
    "dot": "^1.1.3",
 | 
					    "dot": "^1.1.3",
 | 
				
			||||||
    "http-proxy": "^1.18.1",
 | 
					    "http-proxy": "^1.18.1",
 | 
				
			||||||
    "semantic-release": "^17.4.4"
 | 
					    "semantic-release": "^17.4.4",
 | 
				
			||||||
 | 
					    "start-server-and-test": "^1.13.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "release": {
 | 
					  "release": {
 | 
				
			||||||
    "branch": "master",
 | 
					    "branch": "master",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								script/cypress/prepare
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								script/cypress/prepare
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
 | 
				
			||||||
 | 
					dpkg -i erlang-solutions_2.0_all.deb
 | 
				
			||||||
 | 
					apt-get update
 | 
				
			||||||
 | 
					apt-get -y install esl-erlang
 | 
				
			||||||
 | 
					apt-get -y install elixir
 | 
				
			||||||
 | 
					mix local.hex --force
 | 
				
			||||||
 | 
					mix local.rebar --force
 | 
				
			||||||
 | 
					mix deps.get
 | 
				
			||||||
 | 
					mix deps.compile
 | 
				
			||||||
 | 
					mix npm.install
 | 
				
			||||||
 | 
					mix ecto.create
 | 
				
			||||||
 | 
					mix ecto.migrate
 | 
				
			||||||
 | 
					npm ci
 | 
				
			||||||
		Loading…
	
		Reference in a new issue