mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +01:00
Add Cypress for client portal UI tests
This commit is contained in:
parent
8886a4a33d
commit
6880e67210
@ -54,6 +54,7 @@ use Database\Factories\BankTransactionRuleFactory;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use stdClass;
|
||||
@ -203,6 +204,22 @@ class CreateSingleAccount extends Command
|
||||
'applies_to' => (bool)rand(0,1) ? 'CREDIT' : 'DEBIT',
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id,
|
||||
'name' => 'cypress'
|
||||
]);
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
'email' => 'cypress@example.com',
|
||||
'password' => Hash::make('password'),
|
||||
]);
|
||||
|
||||
|
||||
$this->info('Creating '.$this->count.' clients');
|
||||
|
||||
for ($x = 0; $x < $this->count; $x++) {
|
||||
@ -356,7 +373,7 @@ class CreateSingleAccount extends Command
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
'email' => 'user@example.com'
|
||||
'email' => 'user@example.com',
|
||||
]);
|
||||
|
||||
ClientContact::factory()->count(rand(1, 2))->create([
|
||||
|
@ -101,6 +101,7 @@
|
||||
"darkaonline/l5-swagger": "8.1.0",
|
||||
"fakerphp/faker": "^1.14",
|
||||
"filp/whoops": "^2.7",
|
||||
"laracasts/cypress": "^3.0",
|
||||
"laravel/dusk": "^6.15",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
"nunomaduro/collision": "^6.1",
|
||||
|
61
composer.lock
generated
61
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "451d3dbdd5b0a87940e0f8fffadab4ae",
|
||||
"content-hash": "fee0057b8444e2a245cea87dab6c1b3a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "afosto/yaac",
|
||||
@ -13859,6 +13859,65 @@
|
||||
},
|
||||
"time": "2020-07-09T08:09:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laracasts/cypress",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laracasts/cypress.git",
|
||||
"reference": "9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laracasts/cypress/zipball/9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5",
|
||||
"reference": "9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^6.0|^7.0|^8.0|^9.0",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.0|^7.0",
|
||||
"phpunit/phpunit": "^8.0|^9.5.10",
|
||||
"spatie/laravel-ray": "^1.29"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laracasts\\Cypress\\CypressServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laracasts\\Cypress\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeffrey Way",
|
||||
"email": "jeffrey@laracasts.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Laravel Cypress Boilerplate",
|
||||
"homepage": "https://github.com/laracasts/cypress",
|
||||
"keywords": [
|
||||
"cypress",
|
||||
"laracasts"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laracasts/cypress/issues",
|
||||
"source": "https://github.com/laracasts/cypress/tree/3.0.0"
|
||||
},
|
||||
"time": "2022-06-27T13:49:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/dusk",
|
||||
"version": "v6.25.2",
|
||||
|
19
cypress.config.js
vendored
Normal file
19
cypress.config.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
chromeWebSecurity: false,
|
||||
retries: 2,
|
||||
defaultCommandTimeout: 5000,
|
||||
watchForFileChanges: false,
|
||||
videosFolder: 'tests/cypress/videos',
|
||||
screenshotsFolder: 'tests/cypress/screenshots',
|
||||
fixturesFolder: 'tests/cypress/fixture',
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
return require('./tests/cypress/plugins/index.js')(on, config)
|
||||
},
|
||||
baseUrl: 'http://ninja.test:8000/',
|
||||
specPattern: 'tests/cypress/integration/**/*.cy.{js,jsx,ts,tsx}',
|
||||
supportFile: 'tests/cypress/support/index.js',
|
||||
},
|
||||
})
|
@ -118,67 +118,23 @@ class RandomDataSeeder extends Seeder
|
||||
'settings' => null,
|
||||
]);
|
||||
|
||||
$u2 = User::where('email', 'demo@invoiceninja.com')->first();
|
||||
|
||||
if (! $u2) {
|
||||
$u2 = User::factory()->create([
|
||||
'email' => 'demo@invoiceninja.com',
|
||||
'password' => Hash::make('demo'),
|
||||
'account_id' => $account->id,
|
||||
'confirmation_code' => $this->createDbHash(config('database.default')),
|
||||
]);
|
||||
|
||||
$company_token = CompanyToken::create([
|
||||
'user_id' => $u2->id,
|
||||
'company_id' => $company->id,
|
||||
'account_id' => $account->id,
|
||||
'name' => 'test token',
|
||||
'token' => 'TOKEN',
|
||||
]);
|
||||
|
||||
$u2->companies()->attach($company->id, [
|
||||
'account_id' => $account->id,
|
||||
'is_owner' => 1,
|
||||
'is_admin' => 1,
|
||||
'is_locked' => 0,
|
||||
'notifications' => CompanySettings::notificationDefaults(),
|
||||
'permissions' => '',
|
||||
'settings' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
|
||||
ClientContact::create([
|
||||
'first_name' => $faker->firstName(),
|
||||
'last_name' => $faker->lastName(),
|
||||
'email' => config('ninja.testvars.username'),
|
||||
'company_id' => $company->id,
|
||||
'password' => Hash::make(config('ninja.testvars.password')),
|
||||
'email_verified_at' => now(),
|
||||
'client_id' =>$client->id,
|
||||
'user_id' => $user->id,
|
||||
'is_primary' => true,
|
||||
'contact_key' => \Illuminate\Support\Str::random(40),
|
||||
]);
|
||||
|
||||
Client::factory()->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company) {
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $c->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
'name' => 'cypress'
|
||||
]);
|
||||
|
||||
ClientContact::factory()->count(5)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $c->id,
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
});
|
||||
$client->number = $client->getNextClientNumber($client);
|
||||
$client->save();
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
'email' => 'cypress@example.com',
|
||||
'password' => Hash::make('password'),
|
||||
]);
|
||||
|
||||
/* Product Factory */
|
||||
Product::factory()->count(2)->create(['user_id' => $user->id, 'company_id' => $company->id]);
|
||||
@ -200,8 +156,6 @@ class RandomDataSeeder extends Seeder
|
||||
|
||||
$invoice = $invoice_calc->build()->getInvoice();
|
||||
|
||||
$invoice->save();
|
||||
|
||||
$invoice->service()->createInvitations()->markSent()->save();
|
||||
|
||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance);
|
||||
@ -220,16 +174,16 @@ class RandomDataSeeder extends Seeder
|
||||
|
||||
$payment->invoices()->save($invoice);
|
||||
|
||||
$payment_hash = new PaymentHash;
|
||||
$payment_hash->hash = Str::random(128);
|
||||
$payment_hash->data = [['invoice_id' => $invoice->hashed_id, 'amount' => $invoice->balance]];
|
||||
$payment_hash->fee_total = 0;
|
||||
$payment_hash->fee_invoice_id = $invoice->id;
|
||||
$payment_hash->save();
|
||||
// $payment_hash = new PaymentHash;
|
||||
// $payment_hash->hash = Str::random(128);
|
||||
// $payment_hash->data = [['invoice_id' => $invoice->hashed_id, 'amount' => $invoice->balance]];
|
||||
// $payment_hash->fee_total = 0;
|
||||
// $payment_hash->fee_invoice_id = $invoice->id;
|
||||
// $payment_hash->save();
|
||||
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
|
||||
|
||||
$payment->service()->updateInvoicePayment($payment_hash);
|
||||
// $payment->service()->updateInvoicePayment($payment_hash);
|
||||
|
||||
// UpdateInvoicePayment::dispatchNow($payment, $payment->company);
|
||||
}
|
||||
@ -256,7 +210,6 @@ class RandomDataSeeder extends Seeder
|
||||
|
||||
$credit->service()->createInvitations()->markSent()->save();
|
||||
|
||||
//$invoice->markSent()->save();
|
||||
});
|
||||
|
||||
/* Recurring Invoice Factory */
|
||||
@ -286,14 +239,6 @@ class RandomDataSeeder extends Seeder
|
||||
//$invoice->markSent()->save();
|
||||
});
|
||||
|
||||
$clients = Client::all();
|
||||
|
||||
foreach ($clients as $client) {
|
||||
//$client->getNextClientNumber($client);
|
||||
$client->number = $client->getNextClientNumber($client);
|
||||
$client->save();
|
||||
}
|
||||
|
||||
GroupSetting::create([
|
||||
'company_id' => $company->id,
|
||||
'user_id' => $user->id,
|
||||
|
2478
package-lock.json
generated
2478
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,12 +12,13 @@
|
||||
"@babel/compat-data": "7.15.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"cypress": "^12.3.0",
|
||||
"laravel-mix-purgecss": "^6.0.0",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"@tailwindcss/forms": "^0.3.4",
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"autoprefixer": "^10.3.7",
|
||||
"axios": "^0.25",
|
||||
"card-js": "^1.0.13",
|
||||
|
43
tests/cypress/integration/login.cy.js
vendored
Normal file
43
tests/cypress/integration/login.cy.js
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
describe('Test Login Page', () => {
|
||||
|
||||
it('Shows the Password Reset Pasge.', () => {
|
||||
|
||||
|
||||
cy.visit('/client/password/reset');
|
||||
cy.contains('Password Recovery');
|
||||
|
||||
cy.get('input[name=email]').type('cypress@example.com{enter}');
|
||||
cy.contains('We have e-mailed your password reset link!');
|
||||
|
||||
cy.visit('/client/password/reset');
|
||||
cy.contains('Password Recovery');
|
||||
|
||||
cy.get('input[name=email]').type('nono@example.com{enter}');
|
||||
cy.contains("We can't find a user with that e-mail address.");
|
||||
|
||||
});
|
||||
|
||||
it('Shows the login page.', () => {
|
||||
|
||||
cy.visit('/client/login');
|
||||
cy.contains('Client Portal');
|
||||
|
||||
cy.get('input[name=email]').type('cypress@example.com');
|
||||
cy.get('input[name=password]').type('password{enter}');
|
||||
cy.url().should('include', '/invoices');
|
||||
|
||||
cy.visit('/client/recurring_invoices').contains('Recurring Invoices');
|
||||
cy.visit('/client/payments').contains('Payments');
|
||||
cy.visit('/client/quotes').contains('Quotes');
|
||||
cy.visit('/client/credits').contains('Credits');
|
||||
cy.visit('/client/payment_methods').contains('Payment Methods');
|
||||
cy.visit('/client/documents').contains('Documents');
|
||||
cy.visit('/client/statement').contains('Statement');
|
||||
cy.visit('/client/subscriptions').contains('Subscriptions');
|
||||
|
||||
cy.get('[data-ref="client-profile-dropdown"]').click();
|
||||
cy.get('[data-ref="client-profile-dropdown-settings"]').click();
|
||||
cy.contains('Client Information');
|
||||
});
|
||||
|
||||
});
|
23
tests/cypress/plugins/index.js
vendored
Normal file
23
tests/cypress/plugins/index.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/// <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}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
|
||||
on('task', require('./swap-env'));
|
||||
};
|
21
tests/cypress/plugins/swap-env.js
vendored
Normal file
21
tests/cypress/plugins/swap-env.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
let fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
activateCypressEnvFile() {
|
||||
if (fs.existsSync('.env.cypress')) {
|
||||
fs.renameSync('.env', '.env.backup');
|
||||
fs.renameSync('.env.cypress', '.env');
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
activateLocalEnvFile() {
|
||||
if (fs.existsSync('.env.backup')) {
|
||||
fs.renameSync('.env', '.env.cypress');
|
||||
fs.renameSync('.env.backup', '.env');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
3
tests/cypress/support/assertions.js
vendored
Normal file
3
tests/cypress/support/assertions.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Cypress.Commands.add('assertRedirect', path => {
|
||||
cy.location('pathname').should('eq', `/${path}`.replace(/^\/\//, '/'));
|
||||
});
|
92
tests/cypress/support/index.d.ts
vendored
Normal file
92
tests/cypress/support/index.d.ts
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable<Subject> {
|
||||
/**
|
||||
* Log in the user with the given attributes, or create a new user and then log them in.
|
||||
*
|
||||
* @example
|
||||
* cy.login()
|
||||
* cy.login({ id: 1 })
|
||||
*/
|
||||
login(attributes?: object): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Log out the current user.
|
||||
*
|
||||
* @example
|
||||
* cy.logout()
|
||||
*/
|
||||
logout(): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Fetch the currently authenticated user.
|
||||
*
|
||||
* @example
|
||||
* cy.currentUser()
|
||||
*/
|
||||
currentUser(): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Fetch a CSRF token from the server.
|
||||
*
|
||||
* @example
|
||||
* cy.logout()
|
||||
*/
|
||||
csrfToken(): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Fetch a fresh list of URI routes from the server.
|
||||
*
|
||||
* @example
|
||||
* cy.logout()
|
||||
*/
|
||||
refreshRoutes(): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Create and persist a new Eloquent record using Laravel model factories.
|
||||
*
|
||||
* @example
|
||||
* cy.create('App\\User');
|
||||
* cy.create('App\\User', 2);
|
||||
* cy.create('App\\User', 2, { active: false });
|
||||
* cy.create({ model: 'App\\User', state: ['guest'], relations: ['profile'], count: 2 }
|
||||
*/
|
||||
create(): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Refresh the database state using Laravel's migrate:fresh command.
|
||||
*
|
||||
* @example
|
||||
* cy.refreshDatabase()
|
||||
* cy.refreshDatabase({ '--drop-views': true }
|
||||
*/
|
||||
refreshDatabase(options?: object): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Run Artisan's db:seed command.
|
||||
*
|
||||
* @example
|
||||
* cy.seed()
|
||||
* cy.seed('PlansTableSeeder')
|
||||
*/
|
||||
seed(seederClass?: string): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Run an Artisan command.
|
||||
*
|
||||
* @example
|
||||
* cy.artisan()
|
||||
*/
|
||||
artisan(command: string, parameters?: object, options?: object): Chainable<any>;
|
||||
|
||||
/**
|
||||
* Execute arbitrary PHP on the server.
|
||||
*
|
||||
* @example
|
||||
* cy.php('2 + 2')
|
||||
* cy.php('App\\User::count()')
|
||||
*/
|
||||
php(command: string): Chainable<any>;
|
||||
}
|
||||
}
|
32
tests/cypress/support/index.js
vendored
Normal file
32
tests/cypress/support/index.js
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// ***********************************************************
|
||||
// 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
|
||||
// ***********************************************************
|
||||
|
||||
/// <reference types="./" />
|
||||
|
||||
import './laravel-commands';
|
||||
import './laravel-routes';
|
||||
import './assertions';
|
||||
|
||||
before(() => {
|
||||
cy.task('activateCypressEnvFile', {}, { log: false });
|
||||
cy.artisan('config:clear', {}, { log: false });
|
||||
cy.refreshRoutes();
|
||||
cy.seed("RandomDataSeeder");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('activateLocalEnvFile', {}, { log: false });
|
||||
cy.artisan('config:clear', {}, { log: false });
|
||||
});
|
301
tests/cypress/support/laravel-commands.js
vendored
Normal file
301
tests/cypress/support/laravel-commands.js
vendored
Normal file
@ -0,0 +1,301 @@
|
||||
/**
|
||||
* Create a new user and log them in.
|
||||
*
|
||||
* @param {Object} attributes
|
||||
*
|
||||
* @example cy.login();
|
||||
* cy.login({ name: 'JohnDoe' });
|
||||
* cy.login({ attributes: { name: 'JohnDoe' }, state: 'guest', load: ['comments] });
|
||||
*/
|
||||
Cypress.Commands.add('login', (attributes = {}) => {
|
||||
// Are we using the new object system.
|
||||
let requestBody = attributes.attributes || attributes.state || attributes.load ? attributes : { attributes };
|
||||
|
||||
return cy
|
||||
.csrfToken()
|
||||
.then((token) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/login',
|
||||
body: { ...requestBody, _token: token },
|
||||
log: false,
|
||||
});
|
||||
})
|
||||
.then(({ body }) => {
|
||||
Cypress.Laravel.currentUser = body;
|
||||
|
||||
Cypress.log({
|
||||
name: 'login',
|
||||
message: JSON.stringify(body),
|
||||
consoleProps: () => ({ user: body }),
|
||||
});
|
||||
})
|
||||
.its('body', { log: false });
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch the currently authenticated user object.
|
||||
*
|
||||
* @example cy.currentUser();
|
||||
*/
|
||||
Cypress.Commands.add('currentUser', () => {
|
||||
return cy.csrfToken().then((token) => {
|
||||
return cy
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/current-user',
|
||||
body: { _token: token },
|
||||
log: false,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.body) {
|
||||
cy.log('No authenticated user found.');
|
||||
}
|
||||
|
||||
Cypress.Laravel.currentUser = response?.body;
|
||||
|
||||
return response?.body;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Logout the current user.
|
||||
*
|
||||
* @example cy.logout();
|
||||
*/
|
||||
Cypress.Commands.add('logout', () => {
|
||||
return cy
|
||||
.csrfToken()
|
||||
.then((token) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/logout',
|
||||
body: { _token: token },
|
||||
log: false,
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
Cypress.log({ name: 'logout', message: '' });
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch a CSRF token.
|
||||
*
|
||||
* @example cy.csrfToken();
|
||||
*/
|
||||
Cypress.Commands.add('csrfToken', () => {
|
||||
return cy
|
||||
.request({
|
||||
method: 'GET',
|
||||
url: '/__cypress__/csrf_token',
|
||||
log: false,
|
||||
})
|
||||
.its('body', { log: false });
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch and store all named routes.
|
||||
*
|
||||
* @example cy.refreshRoutes();
|
||||
*/
|
||||
Cypress.Commands.add('refreshRoutes', () => {
|
||||
return cy.csrfToken().then((token) => {
|
||||
return cy
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/routes',
|
||||
body: { _token: token },
|
||||
log: false,
|
||||
})
|
||||
.its('body', { log: false })
|
||||
.then((routes) => {
|
||||
cy.writeFile(Cypress.config().supportFolder + '/routes.json', routes, {
|
||||
log: false,
|
||||
});
|
||||
|
||||
Cypress.Laravel.routes = routes;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Visit the given URL or route.
|
||||
*
|
||||
* @example cy.visit('foo/path');
|
||||
* cy.visit({ route: 'home' });
|
||||
* cy.visit({ route: 'team', parameters: { team: 1 } });
|
||||
*/
|
||||
Cypress.Commands.overwrite('visit', (originalFn, subject, options) => {
|
||||
if (subject.route) {
|
||||
return originalFn({
|
||||
url: Cypress.Laravel.route(subject.route, subject.parameters || {}),
|
||||
method: Cypress.Laravel.routes[subject.route].method[0],
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
return originalFn(subject, options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new Eloquent factory.
|
||||
*
|
||||
* @param {String} model
|
||||
* @param {Number|null} times
|
||||
* @param {Object} attributes
|
||||
*
|
||||
* @example cy.create('App\\User');
|
||||
* cy.create('App\\User', 2);
|
||||
* cy.create('App\\User', 2, { active: false });
|
||||
* cy.create('App\\User', { active: false });
|
||||
* cy.create('App\\User', 2, { active: false });
|
||||
* cy.create('App\\User', 2, { active: false }, ['profile']);
|
||||
* cy.create('App\\User', 2, { active: false }, ['profile'], ['guest']);
|
||||
* cy.create('App\\User', { active: false }, ['profile']);
|
||||
* cy.create('App\\User', { active: false }, ['profile'], ['guest']);
|
||||
* cy.create('App\\User', ['profile']);
|
||||
* cy.create('App\\User', ['profile'], ['guest']);
|
||||
* cy.create({ model: 'App\\User', state: ['guest'], relations: ['profile'], count: 2 }
|
||||
*/
|
||||
Cypress.Commands.add('create', (model, count = 1, attributes = {}, load = [], state = []) => {
|
||||
let requestBody = {};
|
||||
|
||||
if (typeof model !== 'object') {
|
||||
if (Array.isArray(count)) {
|
||||
state = attributes;
|
||||
attributes = {};
|
||||
load = count;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (typeof count === 'object') {
|
||||
state = load;
|
||||
load = attributes;
|
||||
attributes = count;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
requestBody = { model, state, attributes, load, count };
|
||||
} else {
|
||||
requestBody = model;
|
||||
}
|
||||
|
||||
return cy
|
||||
.csrfToken()
|
||||
.then((token) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/factory',
|
||||
body: { ...requestBody, _token: token },
|
||||
log: false,
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
Cypress.log({
|
||||
name: 'create',
|
||||
message: requestBody.model + (requestBody.count > 1 ? ` (${requestBody.count} times)` : ''),
|
||||
consoleProps: () => ({ [model]: response.body }),
|
||||
});
|
||||
})
|
||||
.its('body', { log: false });
|
||||
});
|
||||
|
||||
/**
|
||||
* Refresh the database state.
|
||||
*
|
||||
* @param {Object} options
|
||||
*
|
||||
* @example cy.refreshDatabase();
|
||||
* cy.refreshDatabase({ '--drop-views': true });
|
||||
*/
|
||||
Cypress.Commands.add('refreshDatabase', (options = {}) => {
|
||||
return cy.artisan('migrate:fresh', options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Seed the database.
|
||||
*
|
||||
* @param {String} seederClass
|
||||
*
|
||||
* @example cy.seed();
|
||||
* cy.seed('PlansTableSeeder');
|
||||
*/
|
||||
Cypress.Commands.add('seed', (seederClass = '') => {
|
||||
let options = {};
|
||||
|
||||
if (seederClass) {
|
||||
options['--class'] = seederClass;
|
||||
}
|
||||
|
||||
return cy.artisan('db:seed', options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Trigger an Artisan command.
|
||||
*
|
||||
* @param {String} command
|
||||
* @param {Object} parameters
|
||||
* @param {Object} options
|
||||
*
|
||||
* @example cy.artisan('cache:clear');
|
||||
*/
|
||||
Cypress.Commands.add('artisan', (command, parameters = {}, options = {}) => {
|
||||
options = Object.assign({}, { log: true }, options);
|
||||
|
||||
if (options.log) {
|
||||
Cypress.log({
|
||||
name: 'artisan',
|
||||
message: (() => {
|
||||
let message = command;
|
||||
|
||||
for (let key in parameters) {
|
||||
message += ` ${key}="${parameters[key]}"`;
|
||||
}
|
||||
|
||||
return message;
|
||||
})(),
|
||||
consoleProps: () => ({ command, parameters }),
|
||||
});
|
||||
}
|
||||
|
||||
return cy.csrfToken().then((token) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/artisan',
|
||||
body: { command: command, parameters: parameters, _token: token },
|
||||
log: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Execute arbitrary PHP.
|
||||
*
|
||||
* @param {String} command
|
||||
*
|
||||
* @example cy.php('2 + 2');
|
||||
* cy.php('App\\User::count()');
|
||||
*/
|
||||
Cypress.Commands.add('php', (command) => {
|
||||
return cy
|
||||
.csrfToken()
|
||||
.then((token) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: '/__cypress__/run-php',
|
||||
body: { command: command, _token: token },
|
||||
log: false,
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
Cypress.log({
|
||||
name: 'php',
|
||||
message: command,
|
||||
consoleProps: () => ({ result: response.body.result }),
|
||||
});
|
||||
})
|
||||
.its('body.result', { log: false });
|
||||
});
|
21
tests/cypress/support/laravel-routes.js
vendored
Normal file
21
tests/cypress/support/laravel-routes.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Cypress.Laravel = {
|
||||
routes: {},
|
||||
|
||||
route: (name, parameters = {}) => {
|
||||
assert(
|
||||
Cypress.Laravel.routes.hasOwnProperty(name),
|
||||
`Laravel route "${name}" does not exist.`
|
||||
);
|
||||
|
||||
return ((uri) => {
|
||||
Object.keys(parameters).forEach((parameter) => {
|
||||
uri = uri.replace(
|
||||
new RegExp(`{${parameter}}`),
|
||||
parameters[parameter]
|
||||
);
|
||||
});
|
||||
|
||||
return uri;
|
||||
})(Cypress.Laravel.routes[name].uri);
|
||||
},
|
||||
};
|
5608
tests/cypress/support/routes.json
Normal file
5608
tests/cypress/support/routes.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tests/cypress/videos/login.cy.js.mp4
Normal file
BIN
tests/cypress/videos/login.cy.js.mp4
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user