You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gristlabs_grist-core/test/nbrowser/DocTutorial.ts

311 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import {DocCreationInfo} from 'app/common/DocListAPI';
import {UserAPI} from 'app/common/UserAPI';
import {assert, driver, Key} from 'mocha-webdriver';
import * as gu from 'test/nbrowser/gristUtils';
import {setupTestSuite} from 'test/nbrowser/testUtils';
describe('DocTutorial', function () {
this.timeout(30000);
setupTestSuite();
let doc: DocCreationInfo;
let api: UserAPI;
let session: gu.Session;
const cleanup = setupTestSuite();
before(async () => {
session = await gu.session().teamSite.user('support').login();
doc = await session.tempDoc(cleanup, 'DocTutorial.grist');
api = session.createHomeApi();
await api.updateDoc(doc.id, {type: 'tutorial'});
await api.updateDocPermissions(doc.id, {users: {
'anon@getgrist.com': 'viewers',
'everyone@getgrist.com': 'viewers',
}});
});
describe('when logged out', function () {
before(async () => {
session = await gu.session().anon.login();
});
it('redirects user to log in', async function() {
await session.loadDoc(`/doc/${doc.id}`, false);
await gu.checkLoginPage();
});
});
describe('when logged in', function () {
let forkUrl: string;
before(async () => {
session = await gu.session().teamSite.user('user1').login();
});
afterEach(() => gu.checkForErrors());
it('creates a fork the first time the document is opened', async function() {
await session.loadDoc(`/doc/${doc.id}`);
await driver.wait(async () => {
forkUrl = await driver.getCurrentUrl();
return /~/.test(forkUrl);
});
});
it('shows a popup containing slides generated from the GristDocTutorial table', async function() {
assert.isTrue(await driver.findWait('.test-doc-tutorial-popup', 2000).isDisplayed());
assert.equal(await driver.find('.test-doc-tutorial-popup-title').getText(), 'DocTutorial');
assert.equal(
await driver.findWait('.test-doc-tutorial-popup h1', 2000).getText(),
'Intro'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
'Welcome to the Grist Basics tutorial. We will cover the most important Grist '
+ 'concepts and features. Lets get started.'
);
});
it('is visible on all pages', async function() {
for (const page of ['access-rules', 'raw', 'code', 'settings']) {
await driver.find(`.test-tools-${page}`).click();
assert.isTrue(await driver.find('.test-doc-tutorial-popup').isDisplayed());
}
});
it('does not show the GristDocTutorial page or table', async function() {
assert.deepEqual(await gu.getPageNames(), ['Page 1', 'Page 2']);
await driver.find('.test-tools-raw').click();
await driver.findWait('.test-raw-data-list', 1000);
await gu.waitForServer();
assert.isFalse(await driver.findContent('.test-raw-data-table-id',
/GristDocTutorial/).isPresent());
});
it('only allows users access to their own forks', async function() {
const otherSession = await gu.session().teamSite.user('user2').login();
await driver.navigate().to(forkUrl);
assert.match(await driver.findWait('.test-error-header', 2000).getText(), /Access denied/);
await otherSession.loadDoc(`/doc/${doc.id}`);
let otherForkUrl: string;
await driver.wait(async () => {
otherForkUrl = await driver.getCurrentUrl();
return /~/.test(forkUrl);
});
session = await gu.session().teamSite.user('user1').login();
await driver.navigate().to(otherForkUrl!);
assert.match(await driver.findWait('.test-error-header', 2000).getText(), /Access denied/);
await driver.navigate().to(forkUrl);
await gu.waitForDocToLoad();
});
it('supports navigating to the next or previous slide', async function() {
await driver.findWait('.test-doc-tutorial-popup', 2000);
assert.isTrue(await driver.findWait('.test-doc-tutorial-popup-next', 2000).isDisplayed());
assert.isFalse(await driver.find('.test-doc-tutorial-popup-previous').isDisplayed());
await driver.find('.test-doc-tutorial-popup-next').click();
assert.equal(
await driver.find('.test-doc-tutorial-popup h1').getText(),
'Pages'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup h1 + p').getText(),
'On the left-side panel is a list of pages which are views of your data. Right'
+ ' now, there are two pages, Page 1 and Page 2. You are looking at Page 1.'
);
assert.isTrue(await driver.find('.test-doc-tutorial-popup-next').isDisplayed());
assert.isTrue(await driver.find('.test-doc-tutorial-popup-previous').isDisplayed());
await driver.find('.test-doc-tutorial-popup-previous').click();
assert.equal(
await driver.find('.test-doc-tutorial-popup h1').getText(),
'Intro'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
'Welcome to the Grist Basics tutorial. We will cover the most important Grist '
+ 'concepts and features. Lets get started.'
);
assert.isTrue(await driver.find('.test-doc-tutorial-popup-next').isDisplayed());
assert.isFalse(await driver.find('.test-doc-tutorial-popup-previous').isDisplayed());
});
it('supports navigating to a specific slide', async function() {
const slide3 = await driver.find('.test-doc-tutorial-popup-slide-3');
assert.equal(await slide3.getAttribute('title'), 'Adding Columns and Rows');
await slide3.click();
await driver.find('.test-doc-tutorial-popup-slide-3').click();
assert.equal(
await driver.find('.test-doc-tutorial-popup h1').getText(),
'Adding Columns and Rows'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
"You can add new columns to your table by clicking the + icon"
+ ' to the far right of your column headers.'
);
const slide1 = await driver.find('.test-doc-tutorial-popup-slide-1');
assert.equal(await slide1.getAttribute('title'), 'Intro');
await slide1.click();
assert.equal(
await driver.find('.test-doc-tutorial-popup h1').getText(),
'Intro'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
'Welcome to the Grist Basics tutorial. We will cover the most important Grist '
+ 'concepts and features. Lets get started.'
);
});
it('can open images in a lightbox', async function() {
await driver.find('.test-doc-tutorial-popup img').click();
assert.isTrue(await driver.find('.test-doc-tutorial-lightbox').isDisplayed());
assert.equal(
await driver.find('.test-doc-tutorial-lightbox-image').getAttribute('src'),
'https://www.getgrist.com/wp-content/uploads/2023/03/Row-1-Intro.png'
);
await driver.find('.test-doc-tutorial-lightbox-close').click();
assert.isFalse(await driver.find('.test-doc-tutorial-lightbox').isPresent());
});
it('can be minimized and maximized', async function() {
await driver.find('.test-doc-tutorial-popup-minimize-maximize').click();
assert.isTrue(await driver.find('.test-doc-tutorial-popup-header').isDisplayed());
assert.isFalse(await driver.find('.test-doc-tutorial-popup-body').isPresent());
assert.isFalse(await driver.find('.test-doc-tutorial-popup-footer').isPresent());
await driver.find('.test-doc-tutorial-popup-minimize-maximize').click();
assert.isTrue(await driver.find('.test-doc-tutorial-popup-header').isDisplayed());
assert.isTrue(await driver.find('.test-doc-tutorial-popup-body').isDisplayed());
assert.isTrue(await driver.find('.test-doc-tutorial-popup-footer').isDisplayed());
});
it('remembers the last slide the user had open', async function() {
await driver.find('.test-doc-tutorial-popup-slide-3').click();
// There's a 1000ms debounce in place for updates to the last slide.
await driver.sleep(1000 + 250);
await gu.waitForServer();
await driver.navigate().refresh();
await gu.waitForDocToLoad();
await driver.findWait('.test-doc-tutorial-popup', 2000);
assert.equal(
await driver.findWait('.test-doc-tutorial-popup h1', 2000).getText(),
'Adding Columns and Rows'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
"You can add new columns to your table by clicking the + icon"
+ ' to the far right of your column headers.'
);
});
it('always opens the same fork whenever the document is opened', async function() {
assert.deepEqual(await gu.getVisibleGridCells({cols: [0], rowNums: [1]}), ['Zane Rails']);
await gu.getCell(0, 1).click();
await gu.sendKeys('Redacted', Key.ENTER);
await gu.waitForServer();
await session.loadDoc(`/doc/${doc.id}`);
let currentUrl: string;
await driver.wait(async () => {
currentUrl = await driver.getCurrentUrl();
return /~/.test(forkUrl);
});
assert.equal(currentUrl!, forkUrl);
assert.deepEqual(await gu.getVisibleGridCells({cols: [0], rowNums: [1]}), ['Redacted']);
});
it('skips starting or resuming a tutorial if the open mode is set to default', async function() {
await session.loadDoc(`/doc/${doc.id}/m/default`);
assert.deepEqual(await gu.getPageNames(), ['Page 1', 'Page 2', 'GristDocTutorial']);
await driver.find('.test-tools-raw').click();
await gu.waitForServer();
assert.isTrue(await driver.findContentWait('.test-raw-data-table-id',
/GristDocTutorial/, 2000).isPresent());
assert.isFalse(await driver.find('.test-doc-tutorial-popup').isPresent());
});
it('can restart tutorials', async function() {
// Simulate that the tutorial has been updated since it was forked.
await api.updateDoc(doc.id, {name: 'DocTutorial V2'});
await api.applyUserActions(doc.id, [['AddTable', 'NewTable', [{id: 'A'}]]]);
// Load the current fork of the tutorial.
await driver.navigate().to(forkUrl);
await gu.waitForDocToLoad();
await driver.findWait('.test-doc-tutorial-popup', 2000);
// Check that the new table isn't in the fork.
assert.deepEqual(await gu.getPageNames(), ['Page 1', 'Page 2']);
assert.deepEqual(await gu.getVisibleGridCells({cols: [0], rowNums: [1]}), ['Redacted']);
// Restart the tutorial and wait for a new fork to be created.
await driver.find('.test-doc-tutorial-popup-restart').click();
await driver.find('.test-modal-confirm').click();
await gu.waitForServer();
await driver.findWait('.test-doc-tutorial-popup', 2000);
// Check that progress was reset.
assert.equal(
await driver.findWait('.test-doc-tutorial-popup h1', 2000).getText(),
'Intro'
);
assert.equal(
await driver.find('.test-doc-tutorial-popup p').getText(),
'Welcome to the Grist Basics tutorial. We will cover the most important Grist '
+ 'concepts and features. Lets get started.'
);
// Check that edits were reset.
assert.deepEqual(await gu.getVisibleGridCells({cols: [0], rowNums: [1]}), ['Zane Rails']);
// Check that changes made to the tutorial since the last fork are included.
assert.equal(await driver.find('.test-doc-tutorial-popup-title').getText(),
'DocTutorial V2');
assert.deepEqual(await gu.getPageNames(), ['Page 1', 'Page 2', 'NewTable']);
});
it('redirects to the doc menu when finished', async function() {
await driver.find('.test-doc-tutorial-popup-slide-13').click();
await driver.find('.test-doc-tutorial-popup-next').click();
await driver.findWait('.test-dm-doclist', 2000);
});
});
describe('without tutorial flag set', function () {
before(async () => {
await api.updateDoc(doc.id, {type: null});
session = await gu.session().teamSite.user('user1').login();
await session.loadDoc(`/doc/${doc.id}`);
});
afterEach(() => gu.checkForErrors());
it('shows the GristDocTutorial page and table', async function() {
assert.deepEqual(await gu.getPageNames(),
['Page 1', 'Page 2', 'GristDocTutorial', 'NewTable']);
await gu.openPage('GristDocTutorial');
assert.deepEqual(
await gu.getVisibleGridCells({cols: [1, 2], rowNums: [1]}),
[
"# Intro\n\nWelcome to the Grist Basics tutorial. We will cover"
+ " the most important Grist concepts and features. Lets get"
+ " started.\n\n![Grist Basics Tutorial](\n"
+ "https://www.getgrist.com/wp-content/uploads/2023/03/Row-1-Intro.png)",
'',
]
);
await driver.find('.test-tools-raw').click();
await gu.waitForServer();
assert.isTrue(await driver.findContentWait('.test-raw-data-table-id',
/GristDocTutorial/, 2000).isPresent());
});
it('does not show the tutorial popup', async function() {
assert.isFalse(await driver.find('.test-doc-tutorial-popup').isPresent());
});
});
});