Skip to content

Commit f30881b

Browse files
committed
Add tests on local formgrader and increase time for doc test
1 parent 2aafd7f commit f30881b

File tree

2 files changed

+160
-9
lines changed

2 files changed

+160
-9
lines changed

.github/workflows/test-docs-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
run: |
4949
if [ "${{ matrix.group }}" == "docs" ]; then
5050
echo "GROUP=docs" >> $GITHUB_ENV
51-
echo "TIMEOUT_MINUTES=15" >> $GITHUB_ENV
51+
echo "TIMEOUT_MINUTES=20" >> $GITHUB_ENV
5252
fi
5353
if [ "${{ matrix.group }}" == "python" ]; then
5454
echo "GROUP=python" >> $GITHUB_ENV

nbgrader/tests/ui-tests/formgrader.spec.ts

Lines changed: 159 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test as jupyterLabTest, galata, IJupyterLabPageFixture } from "@jupyterlab/galata";
2-
import { APIRequestContext, expect, Frame } from "@playwright/test";
2+
import { APIRequestContext, expect, Frame, Locator} from "@playwright/test";
33
import * as path from "path";
44
import * as os from "os";
55
import * as fs from "fs";
@@ -27,6 +27,7 @@ let mainPanelTabCount = 1;
2727
const baseTestUse = {
2828
tmpPath: tempPath,
2929
mockSettings: {
30+
...galata.DEFAULT_SETTINGS,
3031
'@jupyterlab/apputils-extension:notification': {
3132
fetchNews: 'false'
3233
}
@@ -59,6 +60,14 @@ test.beforeEach(async ({ request, tmpPath }) => {
5960

6061
const contents = galata.newContentsHelper(request);
6162

63+
if (await contents.fileExists("nbgrader_config.py")) {
64+
await contents.deleteFile("nbgrader_config.py");
65+
}
66+
await contents.uploadFile(
67+
path.resolve(__dirname, "./files/nbgrader_config.py"),
68+
"nbgrader_config.py"
69+
);
70+
6271
await contents.createDirectory(tmpPath);
6372

6473
if (!isWindows) {
@@ -82,14 +91,23 @@ test.afterEach(async ({ request, tmpPath }) => {
8291

8392
const contents = galata.newContentsHelper(request);
8493
await contents.deleteDirectory(tmpPath);
94+
});
8595

86-
if (await contents.fileExists("nbgrader_config.py"))
87-
contents.deleteFile("nbgrader_config.py");
88-
contents.uploadFile(
89-
path.resolve(__dirname, "./files/nbgrader_config.py"),
90-
"nbgrader_config.py"
96+
const openSettings = async (page: IJupyterLabPageFixture): Promise<Locator> => {
97+
await page.evaluate(async () => {
98+
await window.jupyterapp.commands.execute('settingeditor:open');
99+
});
100+
101+
// Activate the settings tab, sometimes it does not automatically.
102+
const settingsTab = page
103+
.getByRole('main')
104+
.locator('.lm-TabBar-tab[data-id="setting-editor"]');
105+
await settingsTab.click();
106+
await page.waitForCondition(
107+
async () => (await settingsTab.getAttribute('aria-selected')) === 'true'
91108
);
92-
});
109+
return (await page.activity.getPanelLocator('Settings')) as Locator;
110+
};
93111

94112
/*
95113
* Create a nbgrader file system
@@ -344,7 +362,6 @@ test("Load manage assignments", async ({ page, baseURL, request, tmpPath }) => {
344362
await createEnv(testDir, tmpPath, exchange_dir, cache_dir, isWindows);
345363
await addCourses(request, tmpPath);
346364
await openFormgrader(page);
347-
348365
// get formgrader iframe and check for breadcrumbs
349366
const iframe = page.mainFrame().childFrames()[0];
350367

@@ -856,3 +873,137 @@ test("Switch views", async ({ page, baseURL, request, tmpPath }) => {
856873
}
857874
}
858875
});
876+
877+
/**
878+
* Local Formgrader.
879+
*/
880+
test.describe('#localFormgrader', () => {
881+
test("Should have formgrader settings", async ({ page, tmpPath }) => {
882+
test.skip(isWindows, "This test does not work on Windows");
883+
884+
if (isNotebook) await page.goto(`tree/${tmpPath}`);
885+
886+
const settings = await openSettings(page);
887+
const formgraderSettings = settings.locator(
888+
'.jp-PluginList-entry[data-id="@jupyter/nbgrader:formgrader"]'
889+
);
890+
await expect(formgraderSettings).toBeVisible();
891+
892+
await formgraderSettings.click();
893+
const settingsList = settings.locator('.jp-SettingsPanel fieldset > .form-group');
894+
await expect(settingsList).toHaveCount(1);
895+
await expect(
896+
settingsList.locator('input').first()
897+
).toHaveAttribute('type', 'checkbox');
898+
await expect(
899+
settingsList.locator('input').first()
900+
).not.toBeChecked();
901+
await expect(
902+
settingsList.locator('label').first()
903+
).toHaveText('Allow local nbgrader config file');
904+
});
905+
906+
test('should add option to open formgrader locally', async ({ page, tmpPath }) => {
907+
if (isNotebook) await page.goto(`tree/${tmpPath}`);
908+
909+
const nbgrader_menu = page.locator(
910+
`${menuPanelId} div.lm-MenuBar-itemLabel:text("Nbgrader")`
911+
);
912+
const formgrader_menu = page.locator(
913+
'#jp-mainmenu-nbgrader li[data-command="nbgrader:open-formgrader-local"]'
914+
);
915+
await nbgrader_menu.click();
916+
expect(formgrader_menu).toHaveCount(0);
917+
918+
const settings = await openSettings(page);
919+
const formgraderSettings = settings.locator(
920+
'.jp-PluginList-entry[data-id="@jupyter/nbgrader:formgrader"]'
921+
);
922+
await formgraderSettings.click();
923+
await settings
924+
.locator('.jp-SettingsPanel fieldset > .form-group input')
925+
.first()
926+
.check();
927+
928+
// wait for the settings to be saved
929+
const settingsTab = page
930+
.getByRole('main')
931+
.locator('.lm-TabBar-tab[data-id="setting-editor"]');
932+
await expect(settingsTab).toHaveAttribute('class', /jp-mod-dirty/);
933+
await expect(settingsTab).not.toHaveAttribute('class', /jp-mod-dirty/);
934+
await nbgrader_menu.click();
935+
expect(formgrader_menu).toHaveCount(1);
936+
});
937+
938+
test('should open formgrader locally', async ({ page, tmpPath }) => {
939+
if (isNotebook) await page.goto(`tree/${tmpPath}`);
940+
941+
const nbgraderMenu = page.locator(
942+
`${menuPanelId} div.lm-MenuBar-itemLabel:text("Nbgrader")`
943+
);
944+
const formgraderMenu = page.locator(
945+
'#jp-mainmenu-nbgrader li[data-command="nbgrader:open-formgrader"]'
946+
);
947+
const localFormgraderMenu = page.locator(
948+
'#jp-mainmenu-nbgrader li[data-command="nbgrader:open-formgrader-local"]'
949+
);
950+
951+
const settings = await openSettings(page);
952+
const formgraderSettings = settings.locator(
953+
'.jp-PluginList-entry[data-id="@jupyter/nbgrader:formgrader"]'
954+
);
955+
await formgraderSettings.click();
956+
await settings
957+
.locator('.jp-SettingsPanel fieldset > .form-group input')
958+
.first()
959+
.check();
960+
961+
// wait for the settings to be saved
962+
const settingsTab = page
963+
.getByRole('main')
964+
.locator('.lm-TabBar-tab[data-id="setting-editor"]');
965+
await expect(settingsTab).toHaveAttribute('class', /jp-mod-dirty/);
966+
await expect(settingsTab).not.toHaveAttribute('class', /jp-mod-dirty/);
967+
968+
// Add a local formgrader in another directory
969+
const newDirectory = path.resolve(testDir, 'localFormgrader');
970+
971+
if (fs.existsSync(newDirectory)) {
972+
fs.rmSync(newDirectory, { recursive: true});
973+
}
974+
fs.mkdirSync(newDirectory);
975+
fs.copyFileSync(
976+
path.resolve(testDir, "nbgrader_config.py"),
977+
path.resolve(testDir, tmpPath, "nbgrader_config.py")
978+
);
979+
980+
var text_to_append = `
981+
c.CourseDirectory.course_id = "test_course"
982+
c.Exchange.root = r"${exchange_dir}"
983+
c.Exchange.cache = r"${cache_dir}"
984+
c.Exchange.assignment_dir = r"${newDirectory}"
985+
986+
`;
987+
988+
fs.appendFileSync(
989+
path.resolve(newDirectory, "nbgrader_config.py"),
990+
text_to_append
991+
);
992+
993+
// open regular formgrader and expect warning because of wrong configuration
994+
await nbgraderMenu.click();
995+
await formgraderMenu.click();
996+
let iframe = page.mainFrame().childFrames()[0];
997+
await (await iframe.frameElement()).contentFrame();
998+
await expect(iframe.locator('#warning-exchange')).toBeAttached();
999+
await page.activity.closeAll();
1000+
1001+
// open local formgrader and expect no warning
1002+
await page.filebrowser.openDirectory('localFormgrader');
1003+
await nbgraderMenu.click();
1004+
await localFormgraderMenu.click();
1005+
iframe = page.mainFrame().childFrames()[0];
1006+
await (await iframe.frameElement()).contentFrame();
1007+
await expect(iframe.locator('#warning-exchange')).not.toBeAttached();
1008+
});
1009+
});

0 commit comments

Comments
 (0)