Unverified Commit 514dfc05 authored by Joseph Baylon's avatar Joseph Baylon Committed by GitHub
Browse files

MM-26074 Cypress Test for MM-T713 - Correct time format for clock mode (#5885)

* MM-26074 Cypress Test for MM-T713 - Correct time format for clock mode

* Fix lint issues

* Simplified formatted time assignment

* Extracted preference api to its own

* Removed resetTimezone

* Updated PreferenceType comment

* Fixed theme import path

* Arrange import order

* Minor wrap cleanup

* Minor wrap cleanup
parent ff29734d
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
module.exports = {
TIME_12_HOUR: 'h:mm A', // no leading zeros
TIME_24_HOUR: 'HH:mm', // with leading zeros
};
......@@ -9,6 +9,10 @@
// Group: @account_setting
import moment from 'moment-timezone';
import * as DATE_TIME_FORMAT from '../../../fixtures/date_time_format';
describe('Account Settings > Display > Clock Display Mode', () => {
const mainMessage = 'Test for clock display mode';
const replyMessage1 = 'Reply 1 for clock display mode';
......@@ -116,21 +120,21 @@ function setClockDisplayTo24Hour() {
setClockDisplayTo('clockFormatB');
}
function verifyClockFormat(isHour12) {
function verifyClockFormat(timeFormat) {
cy.get('time').first().then(($timeEl) => {
cy.wrap($timeEl).invoke('attr', 'datetime').then((dateTimeString) => {
const formattedDateTime = new Date(dateTimeString).toLocaleString('en-US', {hour: 'numeric', minute: 'numeric', hour12: isHour12});
cy.wrap($timeEl).should('be.visible').and('have.text', formattedDateTime);
const formattedTime = moment(dateTimeString).format(timeFormat);
cy.wrap($timeEl).should('be.visible').and('have.text', formattedTime);
});
});
}
function verifyClockFormatIs12Hour() {
verifyClockFormat(true);
verifyClockFormat(DATE_TIME_FORMAT.TIME_12_HOUR);
}
function verifyClockFormatIs24Hour() {
verifyClockFormat(false);
verifyClockFormat(DATE_TIME_FORMAT.TIME_24_HOUR);
}
function verifyClockFormatIs12HourForPostWithMessage(postId, message) {
......
......@@ -12,6 +12,7 @@
import moment from 'moment-timezone';
import {getAdminAccount} from '../../../support/env';
import * as DATE_TIME_FORMAT from '../../../fixtures/date_time_format';
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Account Settings > Display > Timezone Mode', () => {
......@@ -24,12 +25,11 @@ describe('Account Settings > Display > Timezone Mode', () => {
const timezoneCanonical = {type: 'Canonical', actualValue: 'Asia/Hong_Kong', expectedValue: 'Asia/Hong_Kong'};
const timezoneUTC = {type: 'Default', actualValue: 'UTC', expectedValue: 'UTC'};
const timezoneInvalid = {type: 'Invalid', actualValue: 'NZ-Chat', expectedValue: 'UTC'};
const timeFormat = 'h:mm A';
const utcFormattedTimes = [
moment(date1).tz(timezoneUTC.expectedValue).format(timeFormat),
moment(date2).tz(timezoneUTC.expectedValue).format(timeFormat),
moment(date3).tz(timezoneUTC.expectedValue).format(timeFormat),
moment(date4).tz(timezoneUTC.expectedValue).format(timeFormat),
const datesInUTC = [
moment(date1).tz(timezoneUTC.expectedValue),
moment(date2).tz(timezoneUTC.expectedValue),
moment(date3).tz(timezoneUTC.expectedValue),
moment(date4).tz(timezoneUTC.expectedValue),
];
before(() => {
......@@ -40,9 +40,6 @@ describe('Account Settings > Display > Timezone Mode', () => {
},
});
// # Reset timezone
resetTimezone();
// # Create and visit new channel
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
cy.visit(`/${team.name}/channels/${channel.name}`);
......@@ -60,20 +57,15 @@ describe('Account Settings > Display > Timezone Mode', () => {
});
});
after(() => {
// # Reset timezone
resetTimezone();
});
describe('MM-T301 Change timezone automatically', () => {
const automaticTestCases = [
{
timezone: timezoneLocal,
localTimes: [
{postIndex: 0, formattedTime: moment(date1).tz(timezoneLocal.expectedValue).format(timeFormat)},
{postIndex: 1, formattedTime: moment(date2).tz(timezoneLocal.expectedValue).format(timeFormat)},
{postIndex: 2, formattedTime: moment(date3).tz(timezoneLocal.expectedValue).format(timeFormat)},
{postIndex: 3, formattedTime: moment(date4).tz(timezoneLocal.expectedValue).format(timeFormat)},
{postIndex: 0, dateInTimezone: moment(date1).tz(timezoneLocal.expectedValue)},
{postIndex: 1, dateInTimezone: moment(date2).tz(timezoneLocal.expectedValue)},
{postIndex: 2, dateInTimezone: moment(date3).tz(timezoneLocal.expectedValue)},
{postIndex: 3, dateInTimezone: moment(date4).tz(timezoneLocal.expectedValue)},
],
},
];
......@@ -85,10 +77,31 @@ describe('Account Settings > Display > Timezone Mode', () => {
setTimezoneDisplayToAutomatic(testCase.timezone);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + utcFormattedTimes[localTime.postIndex] + ', New: ' + localTime.formattedTime, () => {
// * Verify local time is timezone formatted
verifyLocalTimeIsTimezoneFormatted(localTime);
describe('Clock Mode: 12-hour', () => {
before(() => {
// # Save Clock Display Mode to 12-hour
cy.apiSaveClockDisplayModeTo24HourPreference(false);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + datesInUTC[localTime.postIndex].format(DATE_TIME_FORMAT.TIME_12_HOUR) + ', New: ' + localTime.dateInTimezone.format(DATE_TIME_FORMAT.TIME_12_HOUR), () => {
// * Verify local time is timezone formatted 12-hour
verifyLocalTimeIsTimezoneFormatted12Hour(localTime);
});
});
});
describe('Clock Mode: 24-hour', () => {
before(() => {
// # Save Clock Display Mode to 24-hour
cy.apiSaveClockDisplayModeTo24HourPreference(true);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + datesInUTC[localTime.postIndex].format(DATE_TIME_FORMAT.TIME_24_HOUR) + ', New: ' + localTime.dateInTimezone.format(DATE_TIME_FORMAT.TIME_24_HOUR), () => {
// * Verify local time is timezone formatted 24-hour
verifyLocalTimeIsTimezoneFormatted24Hour(localTime);
});
});
});
});
......@@ -100,28 +113,28 @@ describe('Account Settings > Display > Timezone Mode', () => {
{
timezone: timezoneCanonical,
localTimes: [
{postIndex: 0, formattedTime: moment(date1).tz(timezoneCanonical.expectedValue).format(timeFormat)},
{postIndex: 1, formattedTime: moment(date2).tz(timezoneCanonical.expectedValue).format(timeFormat)},
{postIndex: 2, formattedTime: moment(date3).tz(timezoneCanonical.expectedValue).format(timeFormat)},
{postIndex: 3, formattedTime: moment(date4).tz(timezoneCanonical.expectedValue).format(timeFormat)},
{postIndex: 0, dateInTimezone: moment(date1).tz(timezoneCanonical.expectedValue)},
{postIndex: 1, dateInTimezone: moment(date2).tz(timezoneCanonical.expectedValue)},
{postIndex: 2, dateInTimezone: moment(date3).tz(timezoneCanonical.expectedValue)},
{postIndex: 3, dateInTimezone: moment(date4).tz(timezoneCanonical.expectedValue)},
],
},
{
timezone: timezoneUTC,
localTimes: [
{postIndex: 0, formattedTime: moment(date1).tz(timezoneUTC.expectedValue).format(timeFormat)},
{postIndex: 1, formattedTime: moment(date2).tz(timezoneUTC.expectedValue).format(timeFormat)},
{postIndex: 2, formattedTime: moment(date3).tz(timezoneUTC.expectedValue).format(timeFormat)},
{postIndex: 3, formattedTime: moment(date4).tz(timezoneUTC.expectedValue).format(timeFormat)},
{postIndex: 0, dateInTimezone: moment(date1).tz(timezoneUTC.expectedValue)},
{postIndex: 1, dateInTimezone: moment(date2).tz(timezoneUTC.expectedValue)},
{postIndex: 2, dateInTimezone: moment(date3).tz(timezoneUTC.expectedValue)},
{postIndex: 3, dateInTimezone: moment(date4).tz(timezoneUTC.expectedValue)},
],
},
{
timezone: timezoneInvalid,
localTimes: [
{postIndex: 0, formattedTime: moment(date1).tz(timezoneInvalid.expectedValue).format(timeFormat)},
{postIndex: 1, formattedTime: moment(date2).tz(timezoneInvalid.expectedValue).format(timeFormat)},
{postIndex: 2, formattedTime: moment(date3).tz(timezoneInvalid.expectedValue).format(timeFormat)},
{postIndex: 3, formattedTime: moment(date4).tz(timezoneInvalid.expectedValue).format(timeFormat)},
{postIndex: 0, dateInTimezone: moment(date1).tz(timezoneInvalid.expectedValue)},
{postIndex: 1, dateInTimezone: moment(date2).tz(timezoneInvalid.expectedValue)},
{postIndex: 2, dateInTimezone: moment(date3).tz(timezoneInvalid.expectedValue)},
{postIndex: 3, dateInTimezone: moment(date4).tz(timezoneInvalid.expectedValue)},
],
},
];
......@@ -133,10 +146,31 @@ describe('Account Settings > Display > Timezone Mode', () => {
setTimezoneDisplayToManual(testCase.timezone);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + utcFormattedTimes[localTime.postIndex] + ', New: ' + localTime.formattedTime, () => {
// * Verify local time is timezone formatted
verifyLocalTimeIsTimezoneFormatted(localTime);
describe('Clock Mode: 12-hour', () => {
before(() => {
// # Save Clock Display Mode to 12-hour
cy.apiSaveClockDisplayModeTo24HourPreference(false);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + datesInUTC[localTime.postIndex].format(DATE_TIME_FORMAT.TIME_12_HOUR) + ', New: ' + localTime.dateInTimezone.format(DATE_TIME_FORMAT.TIME_12_HOUR), () => {
// * Verify local time is timezone formatted 12-hour
verifyLocalTimeIsTimezoneFormatted12Hour(localTime);
});
});
});
describe('Clock Mode: 24-hour', () => {
before(() => {
// # Save Clock Display Mode to 24-hour
cy.apiSaveClockDisplayModeTo24HourPreference(true);
});
testCase.localTimes.forEach((localTime) => {
it('Post: ' + localTime.postIndex + ', UTC: ' + datesInUTC[localTime.postIndex].format(DATE_TIME_FORMAT.TIME_24_HOUR) + ', New: ' + localTime.dateInTimezone.format(DATE_TIME_FORMAT.TIME_24_HOUR), () => {
// * Verify local time is timezone formatted 24-hour
verifyLocalTimeIsTimezoneFormatted24Hour(localTime);
});
});
});
});
......@@ -144,13 +178,6 @@ describe('Account Settings > Display > Timezone Mode', () => {
});
});
function resetTimezone() {
cy.apiPatchMe({
locale: 'en',
timezone: {automaticTimezone: '', manualTimezone: 'UTC', useAutomaticTimezone: 'false'},
});
}
function navigateToTimezoneDisplaySettings() {
// # Go to Account Settings
cy.toAccountSettingsModal();
......@@ -222,7 +249,16 @@ function setTimezoneDisplayToManual(timezone) {
setTimezoneDisplayTo(false, timezone);
}
function verifyLocalTimeIsTimezoneFormatted(localTime) {
function verifyLocalTimeIsTimezoneFormatted(localTime, timeFormat) {
// * Verify that the local time of each post is in timezone format
cy.findAllByTestId('postView').eq(localTime.postIndex).find('time', {timeout: TIMEOUTS.HALF_SEC}).should('have.text', localTime.formattedTime);
const formattedTime = localTime.dateInTimezone.format(timeFormat);
cy.findAllByTestId('postView').eq(localTime.postIndex).find('time', {timeout: TIMEOUTS.HALF_SEC}).should('have.text', formattedTime);
}
function verifyLocalTimeIsTimezoneFormatted12Hour(localTime) {
verifyLocalTimeIsTimezoneFormatted(localTime, DATE_TIME_FORMAT.TIME_12_HOUR);
}
function verifyLocalTimeIsTimezoneFormatted24Hour(localTime) {
verifyLocalTimeIsTimezoneFormatted(localTime, DATE_TIME_FORMAT.TIME_24_HOUR);
}
......@@ -91,7 +91,7 @@ describe('Messaging', () => {
testCase.localTimes.forEach((localTime, index) => {
it('post ' + index + ' should match', () => {
// # Change user preference to 12-hour format
setTo24HourTimeFormat(false);
cy.apiSaveClockDisplayModeTo24HourPreference(false);
// # Set user locale and timezone
setLocaleAndTimezone(testCase.locale, testCase.manualTimezone);
......@@ -109,7 +109,7 @@ describe('Messaging', () => {
testCase.localTimes.forEach((localTime, index) => {
it('post ' + index + ' should match', () => {
// # Change user preference to 24-hour format
setTo24HourTimeFormat(true);
cy.apiSaveClockDisplayModeTo24HourPreference(true);
// # Set user locale and timezone
setLocaleAndTimezone(testCase.locale, testCase.manualTimezone);
......@@ -137,16 +137,3 @@ function setLocaleAndTimezone(locale, manualTimezone) {
},
});
}
function setTo24HourTimeFormat(is24Hour) {
cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'use_military_time',
value: is24Hour.toString(),
};
cy.apiSaveUserPreference([preference]);
});
}
......@@ -2,6 +2,7 @@
// See LICENSE.txt for license information.
import './setup';
import './preference';
import './system';
import './team';
import './user';
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/// <reference types="cypress" />
// ***************************************************************
// Each command should be properly documented using JSDoc.
// See https://jsdoc.app/index.html for reference.
// Basic requirements for documentation are the following:
// - Meaningful description
// - Specific link to https://api.mattermost.com
// - Each parameter with `@params`
// - Return value with `@returns`
// - Example usage with `@example`
// Custom command should follow naming convention of having `api` prefix, e.g. `apiLogin`.
// ***************************************************************
declare namespace Cypress {
interface Chainable<Subject = any> {
// *******************************************************************************
// Preferences
// https://api.mattermost.com/#tag/preferences
// *******************************************************************************
/**
* Save a list of the user's preferences.
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
* @param {PreferenceType[]} preferences - List of preference objects
* @param {string} userId - User ID
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
*
* @example
* cy.apiSaveUserPreference([{user_id: 'user-id', category: 'display_settings', name: 'channel_display_mode', value: 'full'}], 'user-id');
*/
apiSaveUserPreference(preferences: PreferenceType[], userId: string): Chainable<Response>;
/**
* Save clock display mode to 24-hour preference.
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
* @param {boolean} is24Hour - true (default) or false for 12-hour
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
*
* @example
* cy.apiSaveClockDisplayModeTo24HourPreference(true);
*/
apiSaveClockDisplayModeTo24HourPreference(is24Hour: boolean): Chainable<Response>;
}
}
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import theme from '../../fixtures/theme.json';
// *****************************************************************************
// Preferences
// https://api.mattermost.com/#tag/preferences
// *****************************************************************************
/**
* Saves user's preference directly via API
* This API assume that the user is logged in and has cookie to access
* @param {Array} preference - a list of user's preferences
*/
Cypress.Commands.add('apiSaveUserPreference', (preferences = [], userId = 'me') => {
return cy.request({
headers: {'X-Requested-With': 'XMLHttpRequest'},
url: `/api/v4/users/${userId}/preferences`,
method: 'PUT',
body: preferences,
});
});
/**
* Saves clock display mode 24-hour preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {Boolean} is24Hour - Either true (default) or false
*/
Cypress.Commands.add('apiSaveClockDisplayModeTo24HourPreference', (is24Hour = true) => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'use_military_time',
value: is24Hour.toString(),
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves channel display mode preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {String} value - Either "full" (default) or "centered"
*/
Cypress.Commands.add('apiSaveChannelDisplayModePreference', (value = 'full') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'channel_display_mode',
value,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves message display preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {String} value - Either "clean" (default) or "compact"
*/
Cypress.Commands.add('apiSaveMessageDisplayPreference', (value = 'clean') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'message_display',
value,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves show markdown preview option preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {String} value - Either "true" to show the options (default) or "false"
*/
Cypress.Commands.add('apiSaveShowMarkdownPreviewPreference', (value = 'true') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'advanced_settings',
name: 'feature_enabled_markdown_preview',
value,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves teammate name display preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {String} value - Either "username" (default), "nickname_full_name" or "full_name"
*/
Cypress.Commands.add('apiSaveTeammateNameDisplayPreference', (value = 'username') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'name_format',
value,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves theme preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {Object} value - theme object. Will pass default value if none is provided.
*/
Cypress.Commands.add('apiSaveThemePreference', (value = JSON.stringify(theme.default)) => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'theme',
name: '',
value,
};
return cy.apiSaveUserPreference([preference]);
});
});
const defaultSidebarSettingPreference = {
grouping: 'by_type',
unreads_at_top: 'true',
favorite_at_top: 'true',
sorting: 'alpha',
};
/**
* Saves theme preference of a user directly via API
* This API assume that the user is logged in and has cookie to access
* @param {Object} value - sidebar settings object. Will pass default value if none is provided.
*/
Cypress.Commands.add('apiSaveSidebarSettingPreference', (value = {}) => {
return cy.getCookie('MMUSERID').then((cookie) => {
const newValue = {
...defaultSidebarSettingPreference,
...value,
};
const preference = {
user_id: cookie.value,
category: 'sidebar_settings',
name: '',
value: JSON.stringify(newValue),
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves the preference on whether to show link and image previews
* This API assume that the user is logged in and has cookie to access
* @param {boolean} show - Either "true" to show link and images previews (default), or "false"
*/
Cypress.Commands.add('apiSaveLinkPreviewsPreference', (show = 'true') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'link_previews',
value: show,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves the preference on whether to show link and image previews expanded
* This API assume that the user is logged in and has cookie to access
* @param {boolean} collapse - Either "true" to show previews collapsed (default), or "false"
*/
Cypress.Commands.add('apiSaveCollapsePreviewsPreference', (collapse = 'true') => {
return cy.getCookie('MMUSERID').then((cookie) => {
const preference = {
user_id: cookie.value,
category: 'display_settings',
name: 'collapse_previews',
value: collapse,
};
return cy.apiSaveUserPreference([preference]);
});
});
/**
* Saves tutorial step of a user
* This API assume that the user is logged in and has cookie to access
* @param {string} value - value of tutorial step, e.g. '999' (default, completed tutorial)
*/
Cypress.Commands.add('apiSaveTutorialStep', (userId, value = '999') => {
const preference = {
user_id: userId,
category: 'tutorial_step',
name: userId,
value,
};
return cy.apiSaveUserPreference([preference], userId);
});
......@@ -4,7 +4,6 @@
import xor from 'lodash.xor';
import {getRandomId} from '../utils';
import theme from '../fixtures/theme.json';
import {getAdminAccount} from './env';
......@@ -259,197 +258,6 @@ Cypress.Commands.add('apiEmailTest', () => {
});
});
// *****************************************************************************
// Preferences
// https://api.mattermost.com/#tag/preferences
// *****************************************************************************
/**
* Saves user's preference directly via API
* This API assume that the user is logged in and has cookie to access
* @param {Array} preference - a list of user's preferences
*/