gristlabs_grist-core/test/nbrowser/Dates.ntest.js
Paul Fitzpatrick bcbf57d590 (core) bump mocha version to allow parallel tests; move more tests to core
Summary:
This uses a newer version of mocha in grist-core so that tests can be run in parallel. That allows more tests to be moved without slowing things down overall. Tests moved are venerable browser tests; only the ones that "just work" or worked without too much trouble to are moved, in order to keep the diff from growing too large. Will wrestle with more in follow up.

Parallelism is at the file level, rather than the individual test.

The newer version of mocha isn't needed for grist-saas repo; tests are parallelized in our internal CI by other means. I've chosen to allocate files to workers in a cruder way than our internal CI, based on initial characters rather than an automated process. The automated process would need some reworking to be compatible with mocha running in parallel mode.

Test Plan: this diff was tested first on grist-core, then ported to grist-saas so saas repo history will correctly track history of moved files.

Reviewers: jarek

Reviewed By: jarek

Subscribers: jarek

Differential Revision: https://phab.getgrist.com/D3927
2023-06-27 02:55:34 -04:00

505 lines
20 KiB
JavaScript

import { assert, driver } from 'mocha-webdriver';
import { $, gu, test } from 'test/nbrowser/gristUtil-nbrowser';
describe('Dates.ntest', function() {
const cleanup = test.setupTestSuite(this);
let doc;
before(async function() {
await gu.supportOldTimeyTestCode();
doc = await gu.useFixtureDoc(cleanup, "Hello.grist", true);
await gu.toggleSidePanel("left", "close");
});
afterEach(function() {
return gu.checkForErrors();
});
it('should allow correct datetime reformatting', async function() {
await gu.openSidePane('field');
var cell = await gu.getCellRC(0, 0);
// Move to the first column
await cell.click();
await gu.sendKeys('2008-01-10 9:20pm', $.ENTER);
// Change type to 'DateTime'
await gu.setType('DateTime');
await $('.test-tz-autocomplete').wait().click();
await gu.sendKeys($.DELETE, 'UTC', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), '2008-01-10 9:20pm');
await $('.test-type-transform-apply').wait().click();
await gu.waitForServer();
// Change timezone to 'America/Los_Angeles' and check that the date is correct
await $('.test-tz-autocomplete').wait().click();
await gu.sendKeys('Los An', $.ENTER);
await gu.waitForServer();
assert.equal(await $('.test-tz-autocomplete input').val(), 'America/Los_Angeles');
assert.equal(await cell.text(), '2008-01-10 1:20pm');
// Change format and check that date is reformatted
await gu.dateFormat('MMMM Do, YYYY');
await gu.timeFormat('HH:mm:ss z');
assert.equal(await gu.getCellRC(0, 0).text(), 'January 10th, 2008 13:20:00 PST');
// Change to custom format and check that the date is reformatted
await gu.dateFormat('Custom');
await $('$Widget_dateCustomFormat .kf_text').click();
await gu.sendKeys($.SELECT_ALL, 'dddd', $.ENTER);
await gu.timeFormat("Custom");
await $('$Widget_timeCustomFormat .kf_text').click();
await gu.sendKeys($.SELECT_ALL, 'Hmm', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'Thursday 1320');
});
it('should include a functioning datetime editor', async function() {
var cell = await gu.getCellRC(0, 0);
// DateTime editor should open, separate date and time, and replace incomplete format
// with YYYY-MM-DD
await cell.click();
await gu.sendKeys($.ENTER);
assert.equal(await $('.celleditor_text_editor').first().val(), '2008-01-10');
// Date should be changable by clicking the calendar dates
await $('.celleditor_text_editor').first().sendKeys($.DOWN); // Opens date picker even if window has no focus.
await $('.datepicker .day:contains(19)').wait().click();
await gu.sendKeys($.ENTER);
assert.equal(await cell.text(), 'Saturday 1320');
// Date editor should convert Moment formats to datepicker safe formats
// Date editor should allow tabbing between date and time entry boxes
await gu.dateFormat('MMMM Do, YYYY');
await gu.timeFormat('h:mma');
await cell.click();
await gu.sendKeys($.ENTER);
assert.deepEqual(await $('.celleditor_text_editor').array().val(),
['January 19th, 2008', '1:20pm']);
await gu.sendKeys($.SELECT_ALL, 'February 20th, 2009', $.TAB, '8:15am', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'February 20th, 2009 8:15am');
// DateTime editor should close and save value when the user clicks away
await cell.click();
await gu.sendKeys($.ENTER, $.SELECT_ALL, $.DELETE);
await gu.getCellRC(0, 3).click(); // click away
await gu.waitForServer();
// Since only the date value was removed, the cell should give AltText of the time value
assert.equal(await cell.text(), '8:15am');
assert.hasClass(await cell.find('.field_clip'), 'invalid');
// DateTime editor should close and revert value when the user presses escape
await cell.click();
await gu.sendKeys($.ENTER, 'April 2, 1993', $.ESCAPE);
assert.equal(await cell.text(), '8:15am');
});
it('should allow correct date reformatting', async function() {
var cell = await gu.getCellRC(0, 1);
// Move to the first column
await cell.click();
await gu.sendKeys('2016-01-08', $.ENTER);
// Change type to 'Date'
await gu.setType('Date');
await $('.test-type-transform-apply').wait().click();
await gu.waitForServer(); // Make sure type is set
// Check that the date is correct
await $('$Widget_dateFormat').wait();
assert.equal(await cell.text(), '2016-01-08');
// Change format and check that date is reformatted
await gu.dateFormat('MMMM Do, YYYY');
await gu.waitForServer();
assert.equal(await cell.text(), 'January 8th, 2016');
// Try another format
await gu.dateFormat('DD MMM YYYY');
await gu.waitForServer();
assert.equal(await cell.text(), '08 Jan 2016');
// Change to custom format and check that the date is reformatted
await gu.dateFormat('Custom');
await $('$Widget_dateCustomFormat .kf_text').click();
await gu.sendKeys($.SELECT_ALL, 'dddd', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'Friday');
});
it('should include a functioning date editor', async function() {
var cell = await gu.getCellRC(0, 1);
// Date editor should open and replace incomplete format with YYYY-MM-DD
await cell.click();
await gu.sendKeys($.ENTER);
assert.equal(await $('.celleditor_text_editor').val(), '2016-01-08');
// Date should be changable by clicking the calendar dates
await $('.celleditor_text_editor').sendKeys($.DOWN); // Opens date picker even if window has no focus.
await $('.datepicker .day:contains(19)').wait().click();
await gu.sendKeys($.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'Tuesday');
// Date editor should convert Moment formats to datepicker safe formats
// Date editor should save the date on enter press
await gu.dateFormat('MMMM Do, YYYY');
await cell.click();
await gu.sendKeys($.ENTER);
assert.equal(await $('.celleditor_text_editor').val(), 'January 19th, 2016');
await gu.sendKeys($.SELECT_ALL, 'February 20th, 2016', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'February 20th, 2016');
// Date editor should close and save value when the user clicks away
await cell.click();
await gu.sendKeys($.ENTER, $.SELECT_ALL, $.DELETE);
await gu.getCellRC(0, 3).click(); // click away
await gu.waitForServer();
assert.equal(await cell.text(), '');
// Date editor should close and revert value when the user presses escape
await cell.click();
await gu.sendKeys($.ENTER, 'April 2, 1993', $.ESCAPE);
assert.equal(await cell.text(), '');
});
it('should reload values correctly after reopen', async function() {
await gu.getCellRC(0, 0).click();
await gu.sendKeys('February 20th, 2009', $.TAB, '8:15am', $.ENTER);
await gu.getCellRC(0, 1).click();
await gu.sendKeys('January 19th, 1968', $.ENTER);
await gu.getCellRC(1, 1).click();
await gu.sendKeys($.DELETE);
await gu.waitForServer();
await gu.getCellRC(0, 2).click();
await gu.waitAppFocus(true);
await gu.sendKeys('=');
await $('.test-editor-tooltip-convert').click();
await gu.sendKeys('$A', $.ENTER);
await gu.waitForServer();
await gu.waitAppFocus(true);
await gu.getCellRC(0, 3).click();
await gu.sendKeys('=');
await gu.waitAppFocus(false);
await gu.sendKeys('$B', $.ENTER);
await gu.waitForServer();
assert.deepEqual(await gu.getGridValues({rowNums: [1, 2], cols: ['A', 'B', 'C', 'D']}), [
'February 20th, 2009 8:15am',
'January 19th, 1968',
'2009-02-20 08:15:00-08:00',
'1968-01-19',
'', '', '', ''
]);
// We don't have a quick way to shutdown a document and reopen from scratch. So instead, we'll
// make a copy of the document, and open that to test that values got saved correctly.
// TODO: it would be good to add a way to reload document from scratch, perhaps by reloading
// with a special URL fragment.
await gu.copyDoc(doc.id, true);
assert.deepEqual(await gu.getGridValues({rowNums: [1, 2], cols: ['A', 'B', 'C', 'D']}), [
'February 20th, 2009 8:15am',
'January 19th, 1968',
'2009-02-20 08:15:00-08:00',
'1968-01-19',
'', '', '', ''
]);
});
it('should support shortcuts to insert date/time', async function() {
await gu.openSidePane('field');
// Check the types of the first two columns.
await gu.clickCellRC(0, 0);
await gu.assertType('DateTime');
await gu.clickCellRC(0, 1);
await gu.assertType('Date');
// Insert a few more columns: empty, Text, Numeric.
await addColumn();
await addColumn();
await addColumn();
await gu.clickCellRC(0, 3);
await gu.setType('Numeric');
await gu.clickCellRC(0, 4);
await gu.setType('Text');
// Override Date.now() and timezone in the current browser page to return a consistent value,
// used e.g. for the default for the year and month.
await driver.executeScript(
"Date.now = () => 1477548296087; " + // This value is 2016-10-27 02:04:56.087 EST
"exposeModulesForTests().then(() => { " +
"window.exposedModules.moment.tz.setDefault('America/New_York');" +
"});"
);
async function fillWithShortcuts() {
await gu.toggleSidePanel('right', 'close');
// Type the Date-only shortcut into each cell in the second row.
await gu.clickCellRC(1, 0);
for (var i = 0; i < 6; i++) {
await gu.sendKeys([$.MOD, ';'], $.TAB);
}
// Type the Date-Time shortcut into each cell in the third row.
await gu.clickCellRC(2, 0);
for (i = 0; i < 6; i++) {
await gu.sendKeys([$.MOD, $.SHIFT, ';'], $.TAB);
}
}
// Change document timezone to US/Hawaii (3 hours behind LA, which is TZ of the first column).
// We check that shortcuts for Text/Any columns use the document timezone.
await setGlobalTimezone('US/Hawaii');
await fillWithShortcuts();
// Compare the values. NOTE: this assumes EST timezone for the browser's local time.
assert.deepEqual(await gu.getGridValues({rowNums: [2, 3], cols: [0, 1, 2, 3, 4]}), [
// Note that column A has Los_Angeles timezone set, so time differs from Hawaii.
// Note that Date column gets the date in Hawaii, not local or UTC (both 2016-10-27).
// The originally empty column had its type guessed as Date when the current date was first entered,
// hence "2016-10-26" appears in both rows.
"October 26th, 2016 11:04pm", "October 26th, 2016", "2016-10-26", "0", "2016-10-26",
"October 26th, 2016 11:04pm", "October 26th, 2016", "2016-10-26", "0", "2016-10-26 20:04:56",
]);
// Undo the 8 cells we actually filled in, and check that the empty column reverted to Any
await gu.undo(8);
await gu.clickCellRC(1, 2);
await gu.assertType('Any');
// Change document timezone back to America/New_York.
await setGlobalTimezone('America/New_York');
await fillWithShortcuts();
// Compare the values. NOTE: this assumes EST timezone for the browser's local time.
assert.deepEqual(await gu.getGridValues({rowNums: [2, 3], cols: [0, 1, 2, 3, 4]}), [
// Note that column A has Los_Angeles timezone set, so date differs by one from New_York.
"October 26th, 2016 11:04pm", "October 27th, 2016", "2016-10-27", "0", "2016-10-27",
"October 26th, 2016 11:04pm", "October 27th, 2016", "2016-10-27", "0", "2016-10-27 02:04:56",
]);
});
it('should allow navigating the datepicker with the keyboard', async function() {
// Change the date using the datepicker.
let cell = await gu.getCellRC(0, 1);
await cell.scrollIntoView({inline: "end"}).click();
await gu.sendKeys($.ENTER);
await gu.waitAppFocus(false);
await gu.sendKeys($.UP, $.UP, $.LEFT, $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'January 11th, 1968');
// Do the same in the datetime editor.
cell = await gu.getCellRC(1, 0);
await cell.click();
await gu.sendKeys($.ENTER);
await gu.waitAppFocus(false);
await gu.sendKeys($.UP, $.RIGHT, $.RIGHT, $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'October 28th, 2016 11:04pm');
// Start navigating the datepicker, then start typing to return to using the cell editor.
cell = await gu.getCellRC(1, 1);
await cell.click();
// The first backspace should return to cell edit mode, then the following keys should
// change the year to 2009.
await gu.sendKeys($.ENTER);
await gu.waitAppFocus(false);
await gu.sendKeys($.DOWN, $.RIGHT, $.BACK_SPACE, '9', $.LEFT, $.BACK_SPACE, '0', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'October 27th, 2009');
});
// NOTE: This addresses a bug where typical date entry formats were not recognized.
// See https://phab.getgrist.com/T308
it('should allow using common formats to enter the date', async function() {
let cell = await gu.getCellRC(2, 1);
await cell.click();
await gu.sendKeys('April 2 1993', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'April 2nd, 1993');
cell = await gu.getCellRC(1, 0);
await cell.click();
await gu.sendKeys('December', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), `December 1st, 2016 11:04pm`);
cell = await gu.getCellRC(0, 1);
await cell.click();
await gu.sendKeys('7-Sep', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), `September 7th, 2016`);
await cell.click();
await gu.sendKeys('6/8', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), `June 8th, 2016`);
// The selected format should take precedence over the default format when
// parsing the date. Entering the same thing as before (6/8) will yield a different
// result after changing the format.
await gu.openSidePane('field');
cell = await gu.getCellRC(1, 1);
await cell.click();
await gu.dateFormat('DD-MM-YYYY');
await cell.click();
await gu.sendKeys('6/8', $.ENTER);
await gu.waitForServer();
await gu.dateFormat('MMMM Do, YYYY');
assert.equal(await cell.text(), `August 6th, 2016`);
cell = await gu.getCellRC(2, 1);
await cell.click();
await gu.sendKeys('1937', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), `January 1st, 1937`);
});
it('should not attempt to parse non-dates', async function() {
// Should allow AltText
let cell = await gu.getCellRC(2, 1);
await cell.click();
await gu.sendKeys('Applesauce', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), 'Applesauce');
await assert.hasClass(cell.find('.field_clip'), 'invalid');
// Should allow AltText even of numbers that cannot be parsed as dates.
// Manually entered numbers should not be read as timestamps.
cell = await gu.getCellRC(1, 0);
await cell.click();
await gu.sendKeys('100000', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), '100000 11:04pm');
await assert.hasClass(cell.find('.field_clip'), 'invalid');
// Should give AltText if just the time is entered but not the date.
cell = await gu.getCellRC(1, 0);
await cell.click();
await gu.sendKeys($.ENTER, $.TAB, '3', $.ENTER);
await gu.waitForServer();
assert.equal(await cell.text(), '100000 11:04pm 3');
await assert.hasClass(cell.find('.field_clip'), 'invalid');
});
it("should allow working with naive date object", async function() {
await gu.clickCellRC(0, 1);
await gu.sendKeys([$.ALT, '=']);
await gu.waitForServer();
await gu.sendKeys("Diff", $.ENTER);
await gu.waitForServer();
await gu.sendKeys('=');
await gu.waitAppFocus(false);
await gu.sendKeys('($A-DTIME($B)).total_seconds()', $.ENTER);
await gu.waitForServer();
await gu.waitAppFocus();
assert.deepEqual(await gu.getCellRC(0, 2).text(), '-230211900');
// change global timezone should recompute formula
await setGlobalTimezone('Paris');
assert.deepEqual(await gu.getCellRC(0, 2).text(), '-230190300');
});
// NOTE: This tests a specific bug where AltText values in a column that has been coverted
// to a date column do not respond to updates until refresh. This bug was exposed via the
// error dom in FieldBuilder not being re-evaluated after a column transform.
it('should allow deleting AltText values in a newly changed Date column', async function() {
// Change the type to text and enter a text value.
await gu.clickCellRC(0, 1);
await gu.setType('Text');
await gu.applyTypeConversion();
await gu.clickCellRC(2, 1);
await gu.sendKeys('banana', $.ENTER);
await gu.waitForServer();
assert.equal(await gu.getCellRC(2, 1).text(), 'banana');
// Change back to Date and try to remove the text.
await gu.setType('Date');
await $('.test-type-transform-apply').wait().click();
await gu.waitForServer();
assert.equal(await gu.getCellRC(2, 1).text(), 'banana');
await gu.clickCellRC(2, 1);
await gu.sendKeys($.BACK_SPACE);
await gu.waitForServer();
assert.equal(await gu.getCellRC(2, 1).text(), '');
await gu.undo();
});
it("should report informative error when AltText is used for date", async function() {
// Enter a formula column that uses a date.
await gu.clickCellRC(0, 1);
await gu.sendKeys([$.ALT, '=']);
await gu.waitForServer();
await gu.sendKeys("Month", $.ENTER);
await gu.waitForServer();
await gu.sendKeys("=$B.month", $.ENTER);
await gu.waitForServer();
assert.deepEqual(await gu.getGridValues({rowNums: [1, 2, 3, 4], cols: ['B', 'Month']}), [
"June 8th, 2016", "6",
"August 6th, 2016", "8",
"banana", "#Invalid Date: banana",
"", "#AttributeError",
]);
});
it('should default timezone to document\'s timezone', async function() {
// add a DateTime column
await addDateTimeColumn();
await gu.timeFormat('HH:mm:ss');
// BUG: it is required to click somewhere after setting the type of a column for the shortcut to
// work
// TODO: removes gu.getCellRC(1, 3).click() below when its fixed
await gu.getCellRC(1, 3).click();
// get the current date
await gu.sendKeys([$.MOD, $.SHIFT, ';']);
await gu.waitForServer();
const date1 = await gu.getCellRC(1, 3).text();
// check default timezone
assert.equal(await $('.test-tz-autocomplete input').val(), 'Europe/Paris');
// set global document timezone to 'Europe/Paris'
await setGlobalTimezone('America/Los_Angeles');
// add another DateTime column
await addDateTimeColumn();
await gu.timeFormat('HH:mm:ss');
// todo: same as for gu.getCellRC(1, 3).click();
await gu.getCellRC(1, 4).click();
// get the current date
await gu.sendKeys([$.MOD, $.SHIFT, ';']);
await gu.waitForServer();
const date2 = await gu.getCellRC(1, 4).text();
// check default timezone
assert.equal(await $('.test-tz-autocomplete input').val(), 'America/Los_Angeles');
// check that the delta between date1 and date2 is coherent with the delta between
// 'Europe/Paris' and 'America/Los_Angeles' timezones.
const delta = (new Date(date1) - new Date(date2)) / 1000 / 60 / 60;
assert.isAbove(delta, 6);
assert.isBelow(delta, 12);
});
});
async function addDateTimeColumn() {
await addColumn();
return gu.setType('DateTime');
}
async function addColumn() {
await gu.sendKeys([$.ALT, '=']);
await gu.waitForServer();
return gu.sendKeys($.ESCAPE);
}
async function setGlobalTimezone(name) {
await $('.test-user-icon').click(); // open the user menu
await $('.test-dm-doc-settings').click();
await $('.test-tz-autocomplete').click();
await $(`.test-acselect-dropdown li:contains(${name})`).click();
await gu.waitForServer();
await driver.navigate().back();
}