Move /e2e -> /e2e-tests
Этот коммит содержится в:
@@ -0,0 +1,376 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
describe('System Console - after subscription scenarios', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
|
||||
// # Click Subscribe Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment/confirm').as('confirm');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/subscription').as('subscribe');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').clear().type('testaddress');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('teststate');
|
||||
cy.get('#input_postalCode').clear().type('4444');
|
||||
|
||||
// # Click Subscribe button
|
||||
cy.get('.RHS').find('button').last().should('be.enabled').click();
|
||||
|
||||
cy.wait(['@confirm', '@subscribe']);
|
||||
|
||||
// * Check for success message
|
||||
cy.findByText('You are now subscribed to Cloud Professional', {timeout: TIMEOUTS.TEN_SEC}).should('be.visible');
|
||||
|
||||
// # Click Let's go! button
|
||||
cy.get('#payment_complete_header').find('button').should('be.enabled').click();
|
||||
|
||||
// * Check for non existence of 'Your trial has started!' in banner message
|
||||
cy.contains('span', 'Your trial has started!').should('not.exist');
|
||||
|
||||
// * Check for non existence of 'Subscribe now' button in banner message
|
||||
cy.contains('span', 'Upgrade Now').parent().should('not.exist');
|
||||
});
|
||||
|
||||
describe('System Console - Subscription section', () => {
|
||||
it('MM-T4134 Downloading of invoice after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/subscription', 'Subscription');
|
||||
|
||||
cy.get('.BillingSummary__lastInvoice-productName').invoke('text').as('productName');
|
||||
|
||||
cy.get('.BillingSummary__lastInvoice-chargeAmount').invoke('text').as('totalCharge');
|
||||
|
||||
// * Check the content from the downloaded pdf file
|
||||
cy.get('.BillingSummary__lastInvoice-download >a').then((link) => {
|
||||
cy.request({
|
||||
url: link.prop('href'),
|
||||
encoding: 'binary',
|
||||
}).then(
|
||||
(response) => {
|
||||
const fileName = 'subscriptioninvoice';
|
||||
const filePath = Cypress.config('downloadsFolder') + '/' + fileName + '.pdf';
|
||||
cy.writeFile(filePath, response.body, 'binary');
|
||||
cy.task('getPdfContent', filePath).then((data) => {
|
||||
const allLines = data.text.split('\n');
|
||||
const prodLine = allLines.filter((line) => line.includes('Trial period for Cloud Free'));
|
||||
expect(prodLine.length).to.be.equal(1);
|
||||
const amountLine = allLines.filter((line) => line.includes('Amount paid'));
|
||||
expect(amountLine[0].includes('$0.00')).to.be.equal(true);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('System Console - Payment Information section', () => {
|
||||
it('MM-T4167 check for the card details in payment info screen', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('have.text', 'visa ending in 4242');
|
||||
cy.get('span').eq(1).should('have.text', 'Expires 04/2024');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testcity, teststate, 4444');
|
||||
cy.get('div').eq(2).should('have.text', 'IO');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4169 Check for see billing link navigation in edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').parent().then((link) => {
|
||||
const getHref = () => link.prop('href');
|
||||
cy.wrap({href: getHref}).invoke('href').should('contains', '/cloud-billing.html');
|
||||
cy.wrap(link).should('have.attr', 'target', '_new');
|
||||
cy.wrap(link).should('have.attr', 'rel', 'noopener noreferrer');
|
||||
cy.request(link.prop('href')).its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4170 Edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customer');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
cy.wait('@customer');
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment').as('payment');
|
||||
|
||||
cy.intercept('POST', '/api/v4/cloud/payment/confirm').as('confirm');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/subscription').as('subscribe');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.mastercard.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.mastercard.expDate);
|
||||
cy.get('[name="cvc"]').clear().should('be.enabled').type(billing.mastercard.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test newname');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('Algeria{enter}');
|
||||
cy.get('#input_address').clear().type('testnewaddress');
|
||||
cy.get('#input_city').clear().type('testnewcity');
|
||||
cy.get('#input_state').clear().type('testnewstate');
|
||||
cy.get('#input_postalCode').clear().type('3333');
|
||||
|
||||
// # Click Save Credit Card button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
cy.wait(['@payment', '@confirm']);
|
||||
|
||||
cy.wait('@subscribe');
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('have.text', 'mastercard ending in 4444');
|
||||
cy.get('span').eq(1).should('have.text', 'Expires 04/2024');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testnewaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testnewcity, testnewstate, 3333');
|
||||
cy.get('div').eq(2).should('have.text', 'DZ');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4171 disable Save Credit Card button in edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customer');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
cy.wait('@customer');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.mastercard.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.mastercard.expDate);
|
||||
cy.get('[name="cvc"]').clear().should('be.enabled').type(billing.mastercard.cvc);
|
||||
});
|
||||
cy.get('#input_name').should('be.enabled').invoke('val', '');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").should('be.enabled').type('Algeria{enter}');
|
||||
cy.get('#input_address').should('be.enabled').invoke('val', '');
|
||||
cy.get('#input_city').should('be.enabled').invoke('val', '');
|
||||
cy.get('#input_state').should('be.enabled').clear().type('testnewstate');
|
||||
cy.get('#input_postalCode').should('be.enabled').clear().type('3333');
|
||||
|
||||
// * Check for disabling of Save Credit Card button
|
||||
cy.get('#saveSetting').should('not.be.enabled');
|
||||
|
||||
cy.get('#input_name').should('be.enabled').clear().type('test newname');
|
||||
cy.get('#input_address').should('be.enabled').clear().type('testnewaddress');
|
||||
cy.get('#input_address').should('be.enabled').clear().type('testcity');
|
||||
|
||||
// * Check for enabling of Save Credit Card button
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
});
|
||||
|
||||
it('MM-T4172 Cancelling the edit payment info', () => {
|
||||
navigateToBillingScreen('#billing\\/payment_info', 'Payment Information');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// # Click edit button
|
||||
cy.get(' .admin-console__header .back').click();
|
||||
|
||||
// * Check for Payment info header
|
||||
cy.contains('.admin-console__header', 'Payment Information').should('be.visible');
|
||||
|
||||
// # Click edit button
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-editButton').click();
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.unionpay.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.unionpay.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.unionpay.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test newname');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('Albania{enter}');
|
||||
cy.get('#input_address').clear().type('testcanceladdress');
|
||||
cy.get('#input_city').clear().type('testcancelcity');
|
||||
cy.get('#input_state').clear().type('testcanceltate');
|
||||
cy.get('#input_postalCode').clear().type('2222');
|
||||
|
||||
// # Click Cancel button
|
||||
cy.get('.cancel-button').click();
|
||||
|
||||
// * Check for last four digit of card and Expire date
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-cardInfo').within(() => {
|
||||
cy.get('span').eq(0).should('not.have.text', 'unionpay ending in 0005');
|
||||
cy.get('span').eq(1).should('not.have.text', 'Expires 12/2012');
|
||||
});
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.PaymentInfoDisplay__paymentInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('not.have.text', 'testcanceladdress');
|
||||
cy.get('div').eq(1).should('not.have.text', 'testcancelcity, testcanceltate, 2222');
|
||||
cy.get('div').eq(2).should('not.have.text', 'AL');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('System Console - Company Information section', () => {
|
||||
let customerInfo = {};
|
||||
before(() => {
|
||||
cy.intercept('GET', '/api/v4/cloud/customer').as('customerInfo');
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
cy.wait('@customerInfo').its('response.body').then((customerDetails) => {
|
||||
customerInfo = customerDetails;
|
||||
});
|
||||
});
|
||||
it('MM-T4162 Validate the Company address after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', customerInfo.name);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', customerInfo.num_employees);
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', customerInfo.billing_address.line1);
|
||||
if (customerInfo.billing_address.line2 !== '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.line2}`);
|
||||
cy.get('div').eq(2).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(3).should('have.text', customerInfo.billing_address.country);
|
||||
} else if (customerInfo.billing_address.line2 === '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(2).should('have.text', customerInfo.billing_address.country);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4165 Editing billing address of the company after subscription', () => {
|
||||
navigateToBillingScreen('#billing\\/company_info', 'Company Information');
|
||||
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// * Check name of the company
|
||||
cy.get('#input_companyName').should('have.value', customerInfo.name);
|
||||
|
||||
// * Check the no of employees
|
||||
cy.get('#input_numEmployees').should('have.value', customerInfo.num_employees);
|
||||
|
||||
// # Enter the company info
|
||||
cy.get('#input_companyName').clear().type('test company name');
|
||||
cy.get('#input_numEmployees').clear().type('1000');
|
||||
cy.findByText('Same as Billing Address').prev().should('be.checked').click().should('not.be.checked');
|
||||
cy.contains('legend', 'Country').parent().find('.icon-chevron-down').click();
|
||||
cy.contains('legend', 'Country').parent().find("input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').type('testcompanyaddress');
|
||||
cy.get('#input_address2').type('testcompanyaddress2');
|
||||
cy.get('#input_city').clear().type('testcompanycity');
|
||||
cy.get('#input_state').type('testcompnaystate');
|
||||
cy.get('#input_postalCode').type('5555');
|
||||
|
||||
// # Click Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check name of the company after editing it
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', 'test company name');
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '1000');
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', 'testcompanyaddress');
|
||||
cy.get('div').eq(1).should('have.text', 'testcompanyaddress2');
|
||||
cy.get('div').eq(2).should('have.text', 'testcompanycity, testcompnaystate, 5555');
|
||||
cy.get('div').eq(3).should('have.text', 'IO');
|
||||
});
|
||||
|
||||
// # Click on edit company info button again
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// * Check for edited company Info
|
||||
cy.get('#input_companyName').should('have.value', 'test company name');
|
||||
cy.get('#input_numEmployees').should('have.value', '1000');
|
||||
cy.contains('British Indian Ocean Territory').should('exist');
|
||||
cy.get('#input_address').should('have.value', 'testcompanyaddress');
|
||||
cy.get('#input_address2').should('have.value', 'testcompanyaddress2');
|
||||
cy.get('#input_city').should('have.value', 'testcompanycity');
|
||||
cy.get('#input_state').should('have.value', 'testcompnaystate');
|
||||
cy.get('#input_postalCode').should('have.value', '5555');
|
||||
|
||||
// # Enter the company name and no of employees
|
||||
cy.get('#input_companyName').clear().type('test company');
|
||||
cy.get('#input_numEmployees').clear().type('100');
|
||||
|
||||
// # Click to uncheck the 'Same as Billing Address' checkbox
|
||||
cy.findByText('Same as Billing Address').prev().should('not.be.checked').click().should('be.checked');
|
||||
|
||||
// # Click Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for address details
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address').within(() => {
|
||||
cy.get('div').eq(0).should('have.text', customerInfo.billing_address.line1);
|
||||
if (customerInfo.billing_address.line2 !== '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.line2}`);
|
||||
cy.get('div').eq(2).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(3).should('have.text', customerInfo.billing_address.country);
|
||||
} else if (customerInfo.billing_address.line2 === '') {
|
||||
cy.get('div').eq(1).should('have.text', `${customerInfo.billing_address.city}, ${customerInfo.billing_address.state}, ${customerInfo.billing_address.postal_code}`);
|
||||
cy.get('div').eq(2).should('have.text', customerInfo.billing_address.country);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// # navigate to billing screens
|
||||
const navigateToBillingScreen = (linkLocator, headerName) => {
|
||||
cy.get(linkLocator).scrollIntoView().should('be.visible').click();
|
||||
cy.contains('.admin-console__header', headerName).should('be.visible');
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription/invoices', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'in_1Lz8b0I67GP2qpb43kcuMyFP',
|
||||
number: '8D53267B-0006',
|
||||
create_at: 1667263490000,
|
||||
total: 65,
|
||||
tax: 0,
|
||||
status: 'open',
|
||||
description: '',
|
||||
period_start: 1664582400000,
|
||||
period_end: 1667260800000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUYiI67GP2qpb48DXFukcJ',
|
||||
total: 65,
|
||||
quantity: 0.06451612903225806,
|
||||
price_per_unit: 1000,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'in_1LntnKI67GP2qpb4VObu3NgP',
|
||||
number: '8D53267B-0005',
|
||||
create_at: 1664584986000,
|
||||
total: 733,
|
||||
tax: 0,
|
||||
status: 'failed',
|
||||
description: '',
|
||||
period_start: 1661990400000,
|
||||
period_end: 1664582400000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUZ2I67GP2qpb45uTS89eb',
|
||||
total: 733,
|
||||
quantity: 0.7333333333333333,
|
||||
price_per_unit: 999,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'in_1LntnKI67GP2qpb4VObu3NgV',
|
||||
number: '8D53267B-0005',
|
||||
create_at: 1664584986000,
|
||||
total: 733,
|
||||
tax: 0,
|
||||
status: 'paid',
|
||||
description: '',
|
||||
period_start: 1661990400000,
|
||||
period_end: 1664582400000,
|
||||
subscription_id: 'sub_K0AxuWCDoDD9Qq',
|
||||
line_items: [
|
||||
{
|
||||
price_id: 'price_1KLUZ2I67GP2qpb45uTS89eb',
|
||||
total: 733,
|
||||
quantity: 0.7333333333333333,
|
||||
price_per_unit: 999,
|
||||
description: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
current_product_name: 'Cloud Professional',
|
||||
},
|
||||
],
|
||||
});
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_K0AxuWCDoDD9Qq',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Billing History', () => {
|
||||
before(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit the billing history url
|
||||
cy.visit('admin_console/billing/billing_history');
|
||||
|
||||
// * Check for billing history header
|
||||
cy.contains('.admin-console__header', 'Billing History').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T3491_1 Invoice is shown in a table', () => {
|
||||
cy.get('tr.BillingHistory__table-row').as('tableRows');
|
||||
|
||||
// * Check the first row where payment is pending
|
||||
cy.get('@tableRows').eq(0).find('td').eq(0).should('have.text', '10/01/2022');
|
||||
cy.get('@tableRows').eq(0).find('td.BillingHistory__table-total').should('have.text', '$0.65');
|
||||
cy.get('@tableRows').eq(0).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Pending');
|
||||
cy.get('@invoiceRecord').find('.icon-check-circle-outline').should('be.visible');
|
||||
|
||||
// * Check the first row where payment has failed
|
||||
cy.get('@tableRows').eq(1).find('td').eq(0).should('have.text', '09/01/2022');
|
||||
cy.get('@tableRows').eq(1).find('td.BillingHistory__table-total').should('have.text', '$7.33');
|
||||
cy.get('@tableRows').eq(1).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Payment failed');
|
||||
cy.get('@invoiceRecord').find('.icon-alert-outline').should('be.visible');
|
||||
|
||||
// * Check the first row where payment was successfull
|
||||
cy.get('@tableRows').eq(2).find('td').eq(0).should('have.text', '09/01/2022');
|
||||
cy.get('@tableRows').eq(2).find('td.BillingHistory__table-total').should('have.text', '$7.33');
|
||||
cy.get('@tableRows').eq(2).find('div.BillingHistory__paymentStatus').as('invoiceRecord').should('have.text', 'Paid');
|
||||
cy.get('@invoiceRecord').find('.icon-check-circle-outline').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T3491_2 Validate the contents of downloaded PDF invoice', () => {
|
||||
cy.get('tr.BillingHistory__table-row').as('tableRows');
|
||||
|
||||
// * Check for default record's length in grid
|
||||
cy.get('@tableRows').should('have.length', 3);
|
||||
|
||||
// * Check the invoice line
|
||||
cy.get('@tableRows').eq(1).find('td').eq(4).find('a').should('have.attr', 'href').and('include', 'invoices/in_1LntnKI67GP2qpb4VObu3NgP/pdf');
|
||||
cy.get('@tableRows').eq(2).find('td').eq(4).find('a').should('have.attr', 'href').and('include', 'invoices/in_1LntnKI67GP2qpb4VObu3NgV/pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('System Console - Empty Billing Screen', () => {
|
||||
before(() => {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription/invoices', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
],
|
||||
});
|
||||
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit the billing history url
|
||||
cy.visit('admin_console/billing/billing_history');
|
||||
|
||||
// * Check for billing history header
|
||||
cy.contains('.admin-console__header', 'Billing History').should('be.visible');
|
||||
});
|
||||
|
||||
it('should show empty screen picture and link to /cloud-billing.html', () => {
|
||||
cy.get('.BillingHistory__cardHeaderText-bottom').should('have.text', 'All of your invoices will be shown here');
|
||||
cy.get('.BillingHistory__noHistory-link').should('have.text', 'See how billing works').should('have.attr', 'href').and('include', 'cloud/cloud-billing/cloud-billing.html');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,691 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../../../fixtures/timeouts';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscriptionWithLimitsUsage(subscription, withLimits = {}, postsUsed) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
}).as('subscription');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
recurring_interval: 'month',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
recurring_interval: 'month',
|
||||
},
|
||||
],
|
||||
}).as('products');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: withLimits,
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
count: postsUsed,
|
||||
});
|
||||
}
|
||||
|
||||
function simulateSubscription(subscription, withLimits = true) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Free',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Professional',
|
||||
cross_sells_to: 'prod_4',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
recurring_interval: 'month',
|
||||
name: 'Cloud Enterprise',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_4',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 96,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (withLimits) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
messages: {
|
||||
history: 10000,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('Pricing modal', () => {
|
||||
let urlL;
|
||||
let nonAdminUser;
|
||||
|
||||
it('should not show Upgrade button in global header for non admin users', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.apiInitSetup().then(({user, offTopicUrl: url}) => {
|
||||
urlL = url;
|
||||
nonAdminUser = user;
|
||||
simulateSubscription(subscription);
|
||||
cy.apiLogin(user);
|
||||
cy.visit(url);
|
||||
});
|
||||
|
||||
// * Check that Upgrade button does not show
|
||||
cy.get('#UpgradeButton').should('not.exist');
|
||||
});
|
||||
|
||||
it('should check for ability to request upgrades for non admin users on free plans', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
});
|
||||
|
||||
it('should check for ability to request upgrades to enterprise for non admin users on professional monthly plans', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade and it's disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('be.enabled').should('have.text', 'Request admin to upgrade');
|
||||
});
|
||||
|
||||
it('should not allow any requests for upgrades when on enterprise', () => {
|
||||
cy.apiLogout();
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const messageHistoryLimit = 8000;
|
||||
const messagesUsed = 4000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: messageHistoryLimit,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
simulateSubscriptionWithLimitsUsage(subscription, limits, messagesUsed);
|
||||
cy.apiLogin(nonAdminUser);
|
||||
cy.visit(urlL);
|
||||
|
||||
cy.get('#product_switch_menu').click();
|
||||
cy.get('#view_plans_cta').should('be.visible').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that on professsional card there a button for non admin user to request upgrade and it's disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
|
||||
// * Check that on enterprise card there a button for non admin user to request upgrade
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').find('#enterprise_action').should('have.text', 'Request admin to upgrade').should('be.not.enabled');
|
||||
});
|
||||
|
||||
it('should show Upgrade button in global header for admin users and free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Check that Upgrade button shows for admins
|
||||
cy.get('#UpgradeButton').should('exist');
|
||||
|
||||
// * Check for Upgrade button tooltip
|
||||
cy.get('#UpgradeButton').trigger('mouseover').then(() => {
|
||||
cy.get('#upgrade_button_tooltip').should('be.visible').contains('Only visible to system admins');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Upgrade button in global header for admin users and enterprise trial sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// * Check that Upgrade button shows for admins
|
||||
cy.get('#UpgradeButton').should('exist');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').find('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Upgrade').click();
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
|
||||
// * Check that the upgrade button tooltip does not exist on the purchase modal
|
||||
cy.get('#upgrade_button_tooltip').should('not.exist');
|
||||
|
||||
// * Close PurchaseModal
|
||||
cy.get('#closeIcon').click();
|
||||
|
||||
// # Open pricing modal again
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Check for contact sales CTA
|
||||
cy.get('#contact_sales_quote').contains('Contact Sales');
|
||||
|
||||
// * Check that enterprise card action button shows Try free for 30 days
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').contains('Try free for 30 days');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in enterprise trial sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free Downgrade card button exists
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button is not disabled while on enterprise trial
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').should('not.be.disabled');
|
||||
|
||||
// * Check that enterprise card action button is disabled
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').contains('Try free for 30 days');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Upgrade button clicked while in post trial free sku', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button opens purchase modal
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').click();
|
||||
cy.get('.PricingModal__body').should('exist');
|
||||
|
||||
// * Close PurchaseModal
|
||||
cy.get('button.close-x').click();
|
||||
|
||||
// * Contact Sales button shows and Contact sales for quote CTA should not show
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
cy.get('#contact_sales_quote').should('not.exist');
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#enterprise_action').contains('Contact Sales');
|
||||
});
|
||||
|
||||
it('should open pricing modal when Switch to Yearly is button clicked while in monthly professional', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2', //professional monthly
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
|
||||
// * Check that professsional card Switch to Yearly button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENTLY ON MONTHLY BILLING');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('be.enabled').should('have.text', 'Switch to annual billing').click();
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
});
|
||||
|
||||
it('should have Upgrade button disabled while in yearly professional', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4', //professional yearly
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
|
||||
// * Check that professsional card Switch to Yearly button opens purchase modal
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('.planLabel').should('have.text', 'CURRENT PLAN');
|
||||
cy.get('#professional > .bottom > .bottom_container').find('#professional_action').should('not.be.enabled').should('have.text', 'Upgrade');
|
||||
});
|
||||
|
||||
it('should open cloud limits modal when free disclaimer CTA is clicked', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Open cloud limits modal
|
||||
cy.get('#free_plan_data_restrictions_cta').contains('This plan has data restrictions.');
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free_plan_data_restrictions_cta').click();
|
||||
|
||||
cy.get('.CloudUsageModal').should('exist');
|
||||
cy.get('.CloudUsageModal').contains('Cloud Free limits');
|
||||
});
|
||||
|
||||
it('should not show free disclaimer CTA when on legacy starter product that has no limits', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 100000000, // signifies that this subscription has trialled before
|
||||
};
|
||||
cy.simulateSubscription(subscription, false);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * CTA should not show when there are no limits
|
||||
cy.get('#free_plan_data_restrictions_cta').should('not.exist');
|
||||
});
|
||||
|
||||
it('should allow downgrades from professional plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('not.be.disabled').contains('Downgrade');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from enterprise trial', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'true',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.get('#UpgradeButton').should('exist').click();
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from enterprise plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_3',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that free card Downgrade button is disabled
|
||||
cy.get('#pricingModal').should('be.visible');
|
||||
cy.get('#free > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#free_action').should('be.disabled').contains('Downgrade');
|
||||
|
||||
// * Check that professsional card Upgrade button is disabled while on non trial enterprise
|
||||
cy.get('#professional > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#professional_action').should('be.disabled');
|
||||
|
||||
// * Check that Trial button is disabled on enterprise trial
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('should not allow downgrades from yearly plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
cy.get('#pricingModal').get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
cy.get('#pricingModal').get('#free').get('#free_action').should('not.be.disabled').contains('Contact Support');
|
||||
});
|
||||
|
||||
it('should not allow starting a trial from professional plans', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist').should('be.visible');
|
||||
cy.get('.PricingModal__header').contains('Select a plan');
|
||||
|
||||
// * Check that Trial button is disabled on enterprise trial
|
||||
cy.get('#enterprise > .bottom > .bottom_container').should('be.visible');
|
||||
cy.get('#start_cloud_trial_btn').should('be.disabled');
|
||||
});
|
||||
|
||||
it('Should display downgrade modal when downgrading from monthly professional to free', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(urlL);
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
cy.wait(TIMEOUTS.TWO_SEC);
|
||||
|
||||
// * Click the free action (downgrade).
|
||||
cy.get('#free').should('exist');
|
||||
cy.get('#free_action').should('be.enabled').click();
|
||||
|
||||
// * Check that the downgrade modal has appeard.
|
||||
cy.get('div.DowngradeTeamRemovalModal__body').should('exist');
|
||||
});
|
||||
|
||||
it('Should display a "Contact Support" CTA for downgrading when the current subscription is yearly and not on starter', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_4',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Click the free action (downgrade).
|
||||
cy.get('#free').should('exist').contains('Contact Support');
|
||||
cy.get('#free_action').should('be.enabled').click();
|
||||
});
|
||||
|
||||
it('Should not display a "Contact Support" CTA for downgrading when the current subscription is monthly and not on starter', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// # The free action button should not be disabled and contain the text "Downgrade".
|
||||
cy.get('#free').should('exist').contains('Downgrade');
|
||||
cy.get('#free_action').should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
import {getRandomLetter} from '../../../../../utils/index';
|
||||
|
||||
describe('System Console - Company Information section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
|
||||
// # Visit Company Information page
|
||||
cy.visit('/admin_console/billing/company_info');
|
||||
|
||||
// * Check for the Company Information header
|
||||
cy.contains('.admin-console__header', 'Company Information').should('be.visible');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Click on cancel button if exist
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('.cancel-button').length > 0) {
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4164 Save Info button should not be enabled if any one of the mandatory field is filled with invalid data', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on Add Company Information button
|
||||
cy.contains('span', 'Company Information').parent().click();
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter valid company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('test address');
|
||||
cy.get('#input_address2').clear().type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('test');
|
||||
cy.get('#input_postalCode').clear().type('44455');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear postal code
|
||||
cy.get('#input_postalCode').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
|
||||
// # Type valid postal code
|
||||
cy.get('#input_postalCode').type('44456');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear city
|
||||
cy.get('#input_city').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
|
||||
// # Type valid city
|
||||
cy.get('#input_city').type('testcity');
|
||||
|
||||
// * Check save button is enabled
|
||||
cy.get('#saveSetting').should('be.enabled');
|
||||
|
||||
// # Clear company name
|
||||
cy.get('#input_companyName').clear();
|
||||
|
||||
// * Check save button is disabled
|
||||
cy.get('#saveSetting').should('be.disabled');
|
||||
});
|
||||
|
||||
it('MM-T4161 Adding the Company Information', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on Add Company Information button
|
||||
cy.contains('span', 'Company Information').parent().click();
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('Add test address');
|
||||
cy.get('#input_address2').clear().type('Add test address2');
|
||||
cy.get('#input_city').clear().type('Addtestcity');
|
||||
cy.get('#input_state').clear().type('Addteststate');
|
||||
cy.get('#input_postalCode').clear().type('560089');
|
||||
|
||||
// # Click on Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', companyName);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '10');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('have.text', 'British Indian Ocean Territory');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('have.text', 'Addtestcity, Addteststate, 560089');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('have.text', 'Add test address2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('have.text', 'Add test address');
|
||||
});
|
||||
|
||||
it('MM-T4165 Editing the Company Information', () => {
|
||||
const companyName = getRandomLetter(30);
|
||||
|
||||
// # Click on edit Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type(companyName);
|
||||
cy.get('#input_numEmployees').clear().type('10');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('India{enter}');
|
||||
cy.get('#input_address').clear().type('test address');
|
||||
cy.get('#input_address2').clear().type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').clear().type('test');
|
||||
cy.get('#input_postalCode').clear().type('44455');
|
||||
|
||||
// # Click on Save Info button
|
||||
cy.get('#saveSetting').should('be.enabled').click();
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('have.text', companyName);
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('include.text', '10');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('have.text', 'British Indian Ocean Territory');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('have.text', 'testcity, test, 44455');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('have.text', 'test2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('have.text', 'test address');
|
||||
});
|
||||
|
||||
it('MM-T4166 Cancelling of editing of company information details', () => {
|
||||
// # Click Add edit Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Click back button of Edit Company Information
|
||||
cy.contains('span', 'Edit Company Information').prev().click();
|
||||
|
||||
// * Check for back functionality using back button of edit company information screen
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').should('be.visible');
|
||||
|
||||
// # Click Add Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').click();
|
||||
|
||||
// # Enter company information
|
||||
cy.get('#input_companyName').clear().type('CancelcompanyName');
|
||||
cy.get('#input_numEmployees').clear().type('11');
|
||||
cy.get('#DropdownInput_country_dropdown').click();
|
||||
cy.get("#DropdownInput_country_dropdown .DropDown__input > input[type='text']").type('Albania{enter}');
|
||||
cy.get('#input_address').clear().type('canceltest address');
|
||||
cy.get('#input_address2').clear().type('canceltest2');
|
||||
cy.get('#input_city').clear().type('canceltestcity');
|
||||
cy.get('#input_state').clear().type('canceltest');
|
||||
cy.get('#input_postalCode').clear().type('560072');
|
||||
|
||||
// # Click cancel button
|
||||
cy.get('.cancel-button').click();
|
||||
|
||||
// * Check for visibility of Add Company Information button
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-editButton').should('be.visible');
|
||||
|
||||
// * Check for persisted company name
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-name').should('not.have.text', 'CancelcompanyName');
|
||||
|
||||
// * Check for employee number
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-numEmployees > span').should('not.include.text', '11');
|
||||
|
||||
// * Check for country
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(3).should('not.have.text', 'Albania');
|
||||
|
||||
// * Check for city, state and postal code
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(2).should('not.have.text', 'canceltestcity, canceltest, 560072');
|
||||
|
||||
// * Check for address 2
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(1).should('not.have.text', 'canceltest2');
|
||||
|
||||
// * Check for address 1
|
||||
cy.get('.CompanyInfoDisplay__companyInfo-address > div').eq(0).should('not.have.text', 'canceltest address');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
describe('Feedback modal', () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogout();
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
it('Should display feedback modal when downgrading to cloud free', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the free action (downgrade).
|
||||
cy.findByTestId('Exploring other solutions').click();
|
||||
|
||||
// # Click the submit for the downgrade feedback.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * The downgrade modal should exist.
|
||||
cy.findByText('Downgrading your workspace').should('exist');
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal submit button should be disabled if no option is selected', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal shows error state when "other" option is selected but not comments have been provided', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 1, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the other option, requiring extra comments.
|
||||
cy.get('input[value="Other"]').click();
|
||||
|
||||
// # Fill in the comments.
|
||||
cy.findByTestId('FeedbackModal__TextInput').type('Do not need it anymore.');
|
||||
|
||||
// * The submit (Downgrade) button should be enabled.
|
||||
// # Click it.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
});
|
||||
|
||||
it('Downgrade Feedback modal appears and downgrades after team selection modal is submitted', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_2',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
cy.simulateSubscription(subscription);
|
||||
|
||||
// # Intercepts the teams request to avoid team selection modal.
|
||||
cy.intercept('**/api/v4/usage/teams', {statusCode: 200, body: {active: 2, cloud_archived: 0}}).as('teams');
|
||||
|
||||
// # Open the pricing modal
|
||||
cy.visit('/admin_console/billing/subscription?action=show_pricing_modal');
|
||||
|
||||
cy.wait('@teams');
|
||||
|
||||
// * Pricing modal should be open
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
// * Free action (downgrade) should exist.
|
||||
// # Click it.
|
||||
cy.get('#free_action').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Team selection modal should exist.
|
||||
cy.findByText('Confirm Plan Downgrade').should('exist');
|
||||
|
||||
// The test-id is the team id, can't find it in any network requests for interception.
|
||||
// # Click the first team.
|
||||
cy.get('input[name="deleteTeamRadioGroup"]').first().click();
|
||||
|
||||
// Can't seem to get the button via findByText, use css selector instead.
|
||||
cy.get('.DowngradeTeamRemovalModal__buttons > .btn-primary').should('exist').should('be.enabled').click();
|
||||
|
||||
// * Downgrade feedback should exist.
|
||||
cy.findByText('Please share your reason for downgrading').should('exist');
|
||||
|
||||
// * The submit (Downgrade) button should be disabled.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.disabled');
|
||||
|
||||
// # Click the other option, requiring extra comments.
|
||||
cy.get('input[value="Other"]').click();
|
||||
|
||||
// # Fill in the comments.
|
||||
cy.findByTestId('FeedbackModal__TextInput').type('Do not need it anymore.');
|
||||
|
||||
// * The submit (Downgrade) button should be enabled.
|
||||
// # Click it.
|
||||
cy.get('.GenericModal__button.confirm').contains('Downgrade').should('exist').should('be.enabled').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,527 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
import {getAdminAccount} from '../../../../../support/env';
|
||||
|
||||
const admin = getAdminAccount();
|
||||
|
||||
interface Subscription{
|
||||
id: string;
|
||||
product_id: string;
|
||||
is_free_trial: string;
|
||||
trial_end_at: number;
|
||||
}
|
||||
|
||||
interface Limits {
|
||||
messages?: { history: number };
|
||||
teams?: { active: number; teamsLoaded: boolean };
|
||||
files?: { total_storage: number };
|
||||
}
|
||||
|
||||
function simulateFilesLimitReached(fileStorageUsageBytes: number) {
|
||||
cy.intercept('GET', '**/api/v4/usage/storage', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
bytes: fileStorageUsageBytes + 1, // increase workspace usage
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
files: {
|
||||
total_storage: fileStorageUsageBytes,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Move to utils
|
||||
function simulateSubscription(subscription: Subscription, withLimits = {}) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: subscription,
|
||||
}).as('subscription');
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 'prod_1',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_2',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_3',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
}).as('products');
|
||||
|
||||
if (withLimits) {
|
||||
cy.intercept('GET', '**/api/v4/cloud/limits', {
|
||||
statusCode: 200,
|
||||
body: withLimits,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createUsersProcess(team: { id: string }, channel: { id: string }, times: number) {
|
||||
const users = [];
|
||||
for (let i = 0; i < times; i++) {
|
||||
cy.apiCreateUser({prefix: 'other'}).then(({user}) => {
|
||||
users.push(user);
|
||||
cy.apiAddUserToTeam(team.id, user.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
function userGroupsNotification() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#mattermost_feature_custom_user_groups-restricted-indicator').click();
|
||||
}));
|
||||
|
||||
cy.get('#FeatureRestrictedModal').should('exist');
|
||||
|
||||
cy.get('#button-plans').click();
|
||||
|
||||
cy.get('.close').click();
|
||||
}
|
||||
|
||||
function creatNewTeamNotification() {
|
||||
cy.get('.test-team-header').click().then(() => {
|
||||
cy.get('#mattermost_feature_create_multiple_teams-restricted-indicator').click();
|
||||
});
|
||||
cy.get('#FeatureRestrictedModal').should('exist');
|
||||
cy.get('#button-plans').as('notifyButton').should('have.text', 'Notify admin').click();
|
||||
cy.get('@notifyButton').should('have.text', 'Admin notified!');
|
||||
cy.get('@notifyButton').click();
|
||||
cy.get('@notifyButton').should('have.text', 'Already notified!').should('be.disabled');
|
||||
cy.get('.close').click();
|
||||
}
|
||||
|
||||
function createMessageLimitNotification() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function createFilesNotificationForProfessionalFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.findByText('Notify admin').should('be.visible').click();
|
||||
cy.findByText('Admin notified!').should('be.visible').click();
|
||||
cy.findByText('Already notified!').should('be.visible').should('be.disabled');
|
||||
}));
|
||||
}
|
||||
|
||||
function createTrialNotificationForProfessionalFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#view_plans_cta').click();
|
||||
cy.get('#pricingModal').get('#professional').within(() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
});
|
||||
cy.get('#closeIcon').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function createTrialNotificationForEnterpriseFeatures() {
|
||||
cy.get('#product_switch_menu').click().then((() => {
|
||||
cy.get('#view_plans_cta').click();
|
||||
cy.get('#pricingModal').get('#enterprise').within(() => {
|
||||
cy.get('#notify_admin_cta').click();
|
||||
});
|
||||
cy.get('#closeIcon').click();
|
||||
}));
|
||||
}
|
||||
|
||||
function triggerNotifications(url, trial = false, _failOnStatusCode = true) {
|
||||
cy.apiAdminLogin().then(() => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users/trigger-notify-admin-posts',
|
||||
body: {
|
||||
trial_notification: trial,
|
||||
},
|
||||
failOnStatusCode: _failOnStatusCode,
|
||||
});
|
||||
});
|
||||
|
||||
if (url) {
|
||||
cy.visit(url);
|
||||
}
|
||||
}
|
||||
|
||||
function mapFeatureIdToId(id: string) {
|
||||
switch (id) {
|
||||
case 'mattermost.feature.custom_user_groups':
|
||||
return 'Custom User groups';
|
||||
case 'mattermost.feature.create_multiple_teams':
|
||||
return 'Create Multiple Teams';
|
||||
case 'mattermost.feature.unlimited_messages':
|
||||
return 'Unlimited Messages';
|
||||
case 'mattermost.feature.unlimited_file_storage':
|
||||
return 'Unlimited File Storage';
|
||||
case 'mattermost.feature.all_professional':
|
||||
return 'All Professional features';
|
||||
case 'mattermost.feature.all_enterprise':
|
||||
return 'All Enterprise features';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
function deletePost() {
|
||||
// # Delete system-bot message
|
||||
cy.get('@postId').then((postId) => {
|
||||
cy.externalRequest({user: admin, method: 'DELETE', path: `posts/${postId}`});
|
||||
});
|
||||
}
|
||||
function assertNotification(featureId, minimumPlan, totalRequests, requestsCount, teamName, trial = false) {
|
||||
// # Open system-bot and admin DM
|
||||
cy.visit(`/${teamName}/messages/@system-bot`);
|
||||
|
||||
// * Check for the post from the system-bot
|
||||
cy.getLastPostId().as('postId').then((postId) => {
|
||||
if (trial) {
|
||||
cy.get(`#${postId}_message`).then(() => {
|
||||
cy.get('a').contains('Enterprise trial');
|
||||
});
|
||||
} else {
|
||||
cy.get(`#${postId}_message`).contains(`${totalRequests} members of the workspace have requested a workspace upgrade for:`);
|
||||
}
|
||||
|
||||
cy.get(`#${featureId}-title`.replaceAll('.', '_')).contains(mapFeatureIdToId(featureId));
|
||||
|
||||
if (requestsCount >= 5) {
|
||||
cy.get(`#${featureId}-subtitle`.replaceAll('.', '_')).contains(`${requestsCount} members requested access to this feature`);
|
||||
cy.get(`#${postId}_at_sum_of_members_mention`).click().then(() => {
|
||||
cy.get('#notificationFromMembersModal');
|
||||
cy.get('#invitation_modal_title').contains(`Members that requested ${mapFeatureIdToId(featureId)}`).then(() => {
|
||||
cy.get('.close').click();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (minimumPlan === 'Professional plan') {
|
||||
cy.get(`#${featureId}-title`.replaceAll('.', '_')).within(() => {
|
||||
cy.get('#at_plan_mention').click();
|
||||
});
|
||||
|
||||
cy.get('.PricingModal__header').should('exist').then(() => {
|
||||
cy.get('#closeIcon').click();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function assertUpgradeMessageButton(onlyProfessionalFeatures?: boolean) {
|
||||
cy.get('#view_upgrade_options').contains('View upgrade options');
|
||||
cy.get('#view_upgrade_options').click();
|
||||
cy.get('#pricingModal').should('exist');
|
||||
|
||||
if (onlyProfessionalFeatures) {
|
||||
cy.get('.close-x').click();
|
||||
cy.get('#upgrade_to_professional').contains('Upgrade to Professional');
|
||||
cy.get('.PurchaseModal').should('exist');
|
||||
}
|
||||
}
|
||||
|
||||
function assertTrialMessageButton() {
|
||||
cy.get('#learn_more_about_trial').contains('Learn more about trial');
|
||||
cy.get('#learn_more_about_trial').click();
|
||||
cy.get('.LearnMoreTrialModal').should('exist').then(() => {
|
||||
cy.get('.close').click();
|
||||
});
|
||||
|
||||
cy.findByText('View upgrade options').click();
|
||||
cy.get('#pricingModal').should('exist');
|
||||
}
|
||||
|
||||
function testTrialNotifications(subscription, limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl: string;
|
||||
let myAllProfessionalUsers = [];
|
||||
let myAllEnterpriseUsers = [];
|
||||
const ALL_PROFESSIONAL_FEATURES_REQUESTS = 5;
|
||||
const ALL_ENTERPRISE_FEATURES_REQUESTS = 3;
|
||||
const TOTAL = 8;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myAllProfessionalUsers = createUsersProcess(myTeam, myChannel, ALL_PROFESSIONAL_FEATURES_REQUESTS);
|
||||
myAllEnterpriseUsers = createUsersProcess(myTeam, myChannel, ALL_ENTERPRISE_FEATURES_REQUESTS);
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllProfessionalUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createTrialNotificationForProfessionalFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllEnterpriseUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createTrialNotificationForEnterpriseFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, true);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.all_professional', 'Professional plan', TOTAL, ALL_PROFESSIONAL_FEATURES_REQUESTS, myTeam.name, true);
|
||||
assertNotification('mattermost.feature.all_enterprise', 'Enterprise plan', TOTAL, ALL_ENTERPRISE_FEATURES_REQUESTS, myTeam.name, true);
|
||||
assertTrialMessageButton();
|
||||
});
|
||||
|
||||
deletePost();
|
||||
}
|
||||
|
||||
function testFilesNotifications(subscription: Subscription, limits: Limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl;
|
||||
let myAllProfessionalUsers = [];
|
||||
const ALL_PROFESSIONAL_FEATURES_REQUESTS = 5;
|
||||
const TOTAL = 5;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myAllProfessionalUsers = createUsersProcess(myTeam, myChannel, ALL_PROFESSIONAL_FEATURES_REQUESTS);
|
||||
});
|
||||
|
||||
// # Click notify admin to trial on pricing modal
|
||||
cy.then(() => {
|
||||
myAllProfessionalUsers.forEach((user) => {
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createFilesNotificationForProfessionalFeatures();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, false);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.unlimited_file_storage', 'Professional plan', TOTAL, ALL_PROFESSIONAL_FEATURES_REQUESTS, myTeam.name);
|
||||
assertUpgradeMessageButton();
|
||||
});
|
||||
deletePost();
|
||||
}
|
||||
|
||||
function testUpgradeNotifications(subscription, limits) {
|
||||
let myTeam;
|
||||
let myChannel;
|
||||
let myUrl: string;
|
||||
let myMessageLimitUsers = [];
|
||||
let myUnlimitedTeamsUsers = [];
|
||||
let myUserGroupsUsers = [];
|
||||
|
||||
const CREATE_MULTIPLE_TEAMS_USERS = 2;
|
||||
const UNLIMITED_MESSAGES_USERS = 3;
|
||||
const CUSTOM_USER_GROUPS = 5;
|
||||
|
||||
// # Login as an admin and create test users that will click the different notification ctas
|
||||
cy.apiInitSetup().then(({team, channel, offTopicUrl: url}) => {
|
||||
myTeam = team;
|
||||
myChannel = channel;
|
||||
myUrl = url;
|
||||
|
||||
// # Create non admin users
|
||||
myMessageLimitUsers = createUsersProcess(myTeam, myChannel, UNLIMITED_MESSAGES_USERS);
|
||||
myUnlimitedTeamsUsers = createUsersProcess(myTeam, myChannel, CREATE_MULTIPLE_TEAMS_USERS);
|
||||
myUserGroupsUsers = createUsersProcess(myTeam, myChannel, CUSTOM_USER_GROUPS);
|
||||
});
|
||||
|
||||
// # Click notify admin on message limit reached
|
||||
cy.then(() => {
|
||||
myMessageLimitUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
createMessageLimitNotification();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin on team limit reached
|
||||
cy.then(() => {
|
||||
myUnlimitedTeamsUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
cy.wait(['@subscription', '@products']);
|
||||
creatNewTeamNotification();
|
||||
});
|
||||
});
|
||||
|
||||
// # Click notify admin to allow user groups creation
|
||||
cy.then(() => {
|
||||
myUserGroupsUsers.forEach((user) => {
|
||||
cy.clearCookies();
|
||||
simulateSubscription(subscription, limits);
|
||||
cy.apiLogin({...user, password: 'passwd'});
|
||||
cy.visit(`/${myTeam.name}/channels/${myChannel.name}`);
|
||||
userGroupsNotification();
|
||||
});
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
// # Manually trigger saved notifications
|
||||
triggerNotifications(myUrl, false);
|
||||
});
|
||||
|
||||
cy.then(() => {
|
||||
assertNotification('mattermost.feature.custom_user_groups', 'Enterprise plan', 10, CUSTOM_USER_GROUPS, myTeam.name);
|
||||
assertNotification('mattermost.feature.create_multiple_teams', 'Professional plan', 10, CREATE_MULTIPLE_TEAMS_USERS, myTeam.name);
|
||||
assertNotification('mattermost.feature.unlimited_messages', 'Professional plan', 10, UNLIMITED_MESSAGES_USERS, myTeam.name);
|
||||
assertUpgradeMessageButton();
|
||||
});
|
||||
deletePost();
|
||||
}
|
||||
|
||||
describe('Notify Admin', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableAPITriggerAdminNotifications: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
triggerNotifications('', false, false);
|
||||
});
|
||||
|
||||
it('should test trial notifications', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 0, // never trialed before
|
||||
};
|
||||
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
count: 4500,
|
||||
},
|
||||
});
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 8000,
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
testTrialNotifications(subscription, limits);
|
||||
});
|
||||
|
||||
it('should test files upgrade notifications', () => {
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 0, // never trialed before
|
||||
};
|
||||
|
||||
const fileStorageUsageBytes = 11000000000;
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 7000, // test server seeded with around 4k messages
|
||||
},
|
||||
teams: {
|
||||
active: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
files: {
|
||||
total_storage: fileStorageUsageBytes,
|
||||
},
|
||||
};
|
||||
|
||||
simulateFilesLimitReached(fileStorageUsageBytes);
|
||||
testFilesNotifications(subscription, limits);
|
||||
});
|
||||
|
||||
it('should test upgrade notifications', () => {
|
||||
cy.intercept('GET', '**/api/v4/usage/posts', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
count: 7000,
|
||||
},
|
||||
});
|
||||
const subscription = {
|
||||
id: 'sub_test1',
|
||||
product_id: 'prod_1',
|
||||
is_free_trial: 'false',
|
||||
};
|
||||
|
||||
const limits = {
|
||||
messages: {
|
||||
history: 7500,
|
||||
},
|
||||
teams: {
|
||||
active: 0, // no extra teams allowed to be created
|
||||
teamsLoaded: true,
|
||||
},
|
||||
};
|
||||
|
||||
testUpgradeNotifications(subscription, limits);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_Jh6tBLcgWWOOog',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Payment Information section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4120 Validate non existence of Payment Information menu should during the trial period', () => {
|
||||
// * Check for visibility of payment information menu
|
||||
cy.get('#billing\\/payment_info', {timeout: 10000}).should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T5207 should validate admin user is able to submit alternative payment option', () => {
|
||||
cy.intercept('PUT', '/api/v4/cloud/customer', {
|
||||
body: {
|
||||
name: '',
|
||||
email: 'user123@example.mattermost.com',
|
||||
num_employees: 0,
|
||||
monthly_subscription_intent_wire_transfer: '',
|
||||
id: 'uniqueID',
|
||||
creator_id: '123randomId',
|
||||
create_at: 1665763513000,
|
||||
first_purchase_alt_payment_method: '{"ach":false,"wire":false,"other":true,"otherPaymentOption":"Test Payment Option"}',
|
||||
billing_address: {city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: ''},
|
||||
company_address: {city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: ''},
|
||||
payment_method: {type: '',
|
||||
last_four: '',
|
||||
exp_month: 0,
|
||||
exp_year: 0,
|
||||
card_brand: '',
|
||||
name: ''},
|
||||
}}).as('feedbackResponse');
|
||||
cy.get('.UpgradeMattermostCloud__upgradeButton').click();
|
||||
cy.get('button#monthlySubscription').as('paymentFeedbackLink').should('be.visible').should('have.text', 'Looking for other payment options?').click();
|
||||
cy.get('.Form-section-title').should('be.visible');
|
||||
cy.get('input#wire').should('be.not.checked');
|
||||
cy.get('input#ach').should('be.not.checked');
|
||||
cy.get('input#other').should('be.not.checked');
|
||||
cy.get('button#cancelFeedback').should('be.enabled').click();
|
||||
cy.get('@paymentFeedbackLink').click();
|
||||
cy.get('button#submitFeedback').should('be.disabled');
|
||||
|
||||
cy.get('input#wire').as('wireOption').check();
|
||||
cy.get('button#submitFeedback').as('savebutton').should('be.enabled');
|
||||
cy.get('@wireOption').check();
|
||||
|
||||
cy.get('@savebutton').should('be.enabled').click();
|
||||
cy.wait('@feedbackResponse');
|
||||
cy.get('span.savedFeedback__text').should('be.visible').should('have.text', 'Thanks for sharing feedback!');
|
||||
cy.get('button#feedbackSubmitedDone').should('be.enabled').click();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_Jh6tBLcgWWOOog',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/customer', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
name: 'Test environment ',
|
||||
email: 'test.mattermost.com@mattermost.com',
|
||||
num_employees: 12,
|
||||
monthly_subscription_alt_payment_method: '',
|
||||
id: 'oip7khhhkpbk7cjkrf7m66qyas',
|
||||
creator_id: 'iq9xcutqp7bpdramcij939yas',
|
||||
create_at: 1661456270000,
|
||||
billing_address: {
|
||||
city: 'Seattle',
|
||||
country: 'United States',
|
||||
line1: '123 Hello',
|
||||
line2: '',
|
||||
postal_code: '38383',
|
||||
state: 'AK',
|
||||
},
|
||||
company_address: {
|
||||
city: '',
|
||||
country: '',
|
||||
line1: '',
|
||||
line2: '',
|
||||
postal_code: '',
|
||||
state: '',
|
||||
},
|
||||
payment_method: {
|
||||
type: 'card',
|
||||
last_four: '4242',
|
||||
exp_month: 4,
|
||||
exp_year: 2028,
|
||||
card_brand: 'visa',
|
||||
name: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Subscriptions section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
});
|
||||
|
||||
it('MM-T4118 Subscription page UI check', () => {
|
||||
// * Check for Subscription header
|
||||
cy.contains('.admin-console__header', 'Subscription').should('be.visible');
|
||||
|
||||
// * Check for visibility of Trial tag
|
||||
cy.contains('span', 'trial', {timeout: 10000}).should('be.visible');
|
||||
|
||||
// * Check for User count
|
||||
cy.request('/api/v4/analytics/old?name=standard&team_id=').then((response) => {
|
||||
cy.get('.PlanDetails__userCount > span').invoke('text').then((text) => {
|
||||
const userCount = response.body.find((obj) => obj.name === 'unique_user_count');
|
||||
expect(text).to.contain(userCount.value);
|
||||
});
|
||||
});
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').parent().then((link) => {
|
||||
const getHref = () => link.prop('href');
|
||||
cy.wrap({href: getHref}).invoke('href').should('contains', '/cloud-billing.html');
|
||||
cy.wrap(link).should('have.attr', 'target', '_blank');
|
||||
cy.wrap(link).should('have.attr', 'rel', 'noopener noreferrer');
|
||||
cy.request(link.prop('href')).its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T4122 "Upgrade now" navigation and closing of Upgrade window', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// # Click on close button of Upgrade window
|
||||
cy.get('#closeIcon').parent().should('exist').click();
|
||||
|
||||
// * Check for "Your trial has started!" label
|
||||
cy.contains('span', 'Your trial has started!').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4124 Purchase modal UI check', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// * Check for Compare plans navigation
|
||||
cy.contains('span', 'Compare plans').click();
|
||||
|
||||
cy.findByRole('heading', {name: 'Select a plan'}).should('be.visible');
|
||||
cy.findByRole('button', {name: 'Close'}).click();
|
||||
|
||||
// * Check for See how billing works navigation
|
||||
cy.contains('span', 'See how billing works').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T4128 Enable/disable "Upgrade" button in Purchase modal', () => {
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
// # Click on Upgrade Now button on plans modal
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide your payment details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// # Enter card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
|
||||
// # Enter invalid csv
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cvc"]').clear().type(billing.invalidvisa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test user');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
|
||||
// # Enter billing details
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// # Enter invalid card details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.invalidvisa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test user');
|
||||
|
||||
// * Check for disabled Upgrade button for having wrong card details
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @cloud_only @cloud_trial
|
||||
|
||||
import billing from '../../../../../fixtures/client_billing.json';
|
||||
|
||||
function simulateSubscription() {
|
||||
cy.intercept('GET', '**/api/v4/cloud/subscription', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
id: 'sub_test1',
|
||||
is_free_trial: 'true',
|
||||
customer_id: '5zqhakmibpgyix9juiwwkpfnmr',
|
||||
product_id: 'prod_LSBESgGXq9KlLj',
|
||||
seats: 25,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '**/api/v4/cloud/products**', {
|
||||
statusCode: 200,
|
||||
body:
|
||||
[
|
||||
{
|
||||
id: 'prod_LSBESgGXq9KlLj',
|
||||
sku: 'cloud-starter',
|
||||
price_per_seat: 0,
|
||||
name: 'Cloud Free',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_K0AxuWCDoDD9Qq',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 10,
|
||||
name: 'Cloud Professional',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: 'prod_MYrZ0xObCXOyVr',
|
||||
},
|
||||
{
|
||||
id: 'prod_Jh6tBLcgWWOOog',
|
||||
sku: 'cloud-enterprise',
|
||||
price_per_seat: 30,
|
||||
name: 'Cloud Enterprise',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
{
|
||||
id: 'prod_MYrZ0xObCXOyVr',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 96,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_K0AxuWCDoDD9Qq',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('System Console - Subscriptions section', () => {
|
||||
before(() => {
|
||||
// * Check if server has license for Cloud
|
||||
cy.apiRequireLicenseForFeature('Cloud');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
simulateSubscription();
|
||||
|
||||
// # Visit Subscription page
|
||||
cy.visit('/admin_console/billing/subscription');
|
||||
});
|
||||
|
||||
it('MM-T5128 Updating the Usercount input field updates the prices accordingly in the Purchase modal', () => {
|
||||
const professionalYearlySubscription = {
|
||||
id: 'prod_MYrZ0xObCXOyVr',
|
||||
sku: 'cloud-professional',
|
||||
price_per_seat: 8,
|
||||
recurring_interval: 'year',
|
||||
name: 'Cloud Professional Yearly',
|
||||
cross_sells_to: 'prod_K0AxuWCDoDD9Qq',
|
||||
};
|
||||
|
||||
// * Check for User count
|
||||
cy.request('/api/v4/analytics/old?name=standard&team_id=').then((response) => {
|
||||
cy.get('.PlanDetails__userCount > span').invoke('text').then((text) => {
|
||||
const userCount = response.body.find((obj) => obj.name === 'unique_user_count');
|
||||
expect(text).to.contain(userCount.value);
|
||||
|
||||
const count = Number(userCount.value);
|
||||
|
||||
const numMonths = 12;
|
||||
|
||||
const checkValues = (currentCount) => {
|
||||
const totalVal = currentCount * professionalYearlySubscription.price_per_seat * numMonths;
|
||||
cy.get('.RHS').get('.SeatsCalculator__total-value').then((elem) => {
|
||||
const txt = elem.text();
|
||||
const totalValText = txt.replace('$', '').replaceAll(',', '');
|
||||
expect(totalVal.toString()).to.equal(totalValText);
|
||||
});
|
||||
};
|
||||
|
||||
// # Click on Upgrade Now button
|
||||
cy.contains('span', 'Upgrade Now').parent().click();
|
||||
|
||||
// # Click on Professional action button on pricing modal
|
||||
cy.get('#professional_action').click();
|
||||
|
||||
// * Check for "Provide Your Payment Details" label
|
||||
cy.findByText('Provide your payment details').should('be.visible');
|
||||
|
||||
// * check that the price matches the yearly product's price
|
||||
cy.get('.RHS').get('.plan_price_rate_section').contains(professionalYearlySubscription.price_per_seat);
|
||||
cy.get('.RHS').get('#input_UserSeats').should('have.value', count);
|
||||
|
||||
// * check that the prices are correct
|
||||
checkValues(count);
|
||||
|
||||
// # Enter card details and user details
|
||||
cy.uiGetPaymentCardInput().within(() => {
|
||||
cy.get('[name="cardnumber"]').should('be.enabled').clear().type(billing.visa.cardNumber);
|
||||
cy.get('[name="exp-date"]').should('be.enabled').clear().type(billing.visa.expDate);
|
||||
cy.get('[name="cvc"]').should('be.enabled').clear().type(billing.visa.cvc);
|
||||
});
|
||||
cy.get('#input_name').clear().type('test name');
|
||||
cy.findByText('Country').parent().find('.icon-chevron-down').click();
|
||||
cy.findByText('Country').parent().find("input[type='text']").type('India{enter}', {force: true});
|
||||
cy.get('#input_address').type('test1');
|
||||
cy.get('#input_address2').type('test2');
|
||||
cy.get('#input_city').clear().type('testcity');
|
||||
cy.get('#input_state').type('test');
|
||||
cy.get('#input_postalCode').type('444');
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
|
||||
// # Change the user seats field to a value smaller than the current number of users
|
||||
const lessThanUserCount = count - 5;
|
||||
cy.get('#input_UserSeats').clear().type(lessThanUserCount);
|
||||
|
||||
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
||||
checkValues(lessThanUserCount);
|
||||
cy.get('.RHS').get('.Input___customMessage').contains(`Your workspace currently has ${count} users`);
|
||||
|
||||
// * Check that Upgrade button is not enabled
|
||||
cy.get('.RHS').find('button').should('be.disabled');
|
||||
|
||||
// # Change the user seats field to a value bigger than the current number of users
|
||||
const greaterThanUserCount = count + 5;
|
||||
cy.get('#input_UserSeats').clear().type(greaterThanUserCount);
|
||||
|
||||
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
||||
checkValues(greaterThanUserCount);
|
||||
|
||||
// * Check for enable status of Upgrade button
|
||||
cy.get('.RHS').find('button').should('be.enabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Ссылка в новой задаче
Block a user