mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Moving widget tests to core
Summary: - Custom widget tests are now in grist-core - Adding buildtools for grist-plugin-api.js Test Plan: Existing tests Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3617
This commit is contained in:
BIN
test/fixtures/docs/CustomWidget.grist
vendored
Normal file
BIN
test/fixtures/docs/CustomWidget.grist
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/docs/TypeEncoding.grist
vendored
Normal file
BIN
test/fixtures/docs/TypeEncoding.grist
vendored
Normal file
Binary file not shown.
43
test/fixtures/sites/config/index.html
vendored
Normal file
43
test/fixtures/sites/config/index.html
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body style="background: white;">
|
||||
<div id="ready"></div>
|
||||
<div id="access"></div>
|
||||
<div id="readonly"></div>
|
||||
|
||||
<div>onOptions event data:</div>
|
||||
<pre id="onOptions"></pre>
|
||||
|
||||
<div>onRecord event data:</div>
|
||||
<pre id="onRecord"></pre>
|
||||
|
||||
<div>onRecord mapping data:</div>
|
||||
<pre id="onRecordMappings"></pre>
|
||||
|
||||
<div>onRecords event data:</div>
|
||||
<pre id="onRecords"></pre>
|
||||
|
||||
<div>onRecord mappings data:</div>
|
||||
<pre id="onRecordsMappings"></pre>
|
||||
|
||||
<div>configure handler:</div>
|
||||
<pre id="configure"></pre>
|
||||
|
||||
<div>Method input json:</div>
|
||||
<input type="text" id="input" value="" />
|
||||
<div>Method output json:</div>
|
||||
<div id="output"></div>
|
||||
<div>Methods:</div>
|
||||
<button onclick="getOptions()">getOptions</button>
|
||||
<button onclick="setOptions()">setOptions</button>
|
||||
<button onclick="getOption()">getOption</button>
|
||||
<button onclick="setOption()">setOption</button>
|
||||
<button onclick="mappings()">mappings</button>
|
||||
<button onclick="configure()">configure</button>
|
||||
<button onclick="clearOptions()">clearOptions</button>
|
||||
</body>
|
||||
</html>
|
||||
72
test/fixtures/sites/config/page.js
vendored
Normal file
72
test/fixtures/sites/config/page.js
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/* global document, grist, window */
|
||||
|
||||
// Ready message can be configured from url
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const ready = urlParams.get('ready') ? JSON.parse(urlParams.get('ready')) : undefined;
|
||||
|
||||
if (ready && ready.onEditOptions) {
|
||||
ready.onEditOptions = () => {
|
||||
document.getElementById('configure').innerHTML = 'called';
|
||||
};
|
||||
}
|
||||
|
||||
grist.ready(ready);
|
||||
|
||||
grist.onOptions(data => {
|
||||
document.getElementById('onOptions').innerHTML = JSON.stringify(data);
|
||||
});
|
||||
|
||||
grist.onRecord((data, mappings) => {
|
||||
document.getElementById('onRecord').innerHTML = JSON.stringify(data);
|
||||
document.getElementById('onRecordMappings').innerHTML = JSON.stringify(mappings);
|
||||
});
|
||||
|
||||
grist.onRecords((data, mappings) => {
|
||||
document.getElementById('onRecords').innerHTML = JSON.stringify(data);
|
||||
document.getElementById('onRecordsMappings').innerHTML = JSON.stringify(mappings);
|
||||
});
|
||||
|
||||
async function run(handler) {
|
||||
try {
|
||||
document.getElementById('output').innerText = 'waiting...';
|
||||
const result = await handler(JSON.parse(document.getElementById('input').value || '[]'));
|
||||
document.getElementById('output').innerText = result === undefined ? 'undefined' : JSON.stringify(result);
|
||||
} catch (err) {
|
||||
document.getElementById('output').innerText = JSON.stringify({error: err.message || String(err)});
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function getOptions() {
|
||||
return run(() => grist.widgetApi.getOptions());
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function setOptions() {
|
||||
return run(options => grist.widgetApi.setOptions(...options));
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function setOption() {
|
||||
return run(options => grist.widgetApi.setOption(...options));
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function getOption() {
|
||||
return run(options => grist.widgetApi.getOption(...options));
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function clearOptions() {
|
||||
return run(() => grist.widgetApi.clearOptions());
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function mappings() {
|
||||
return run(() => grist.sectionApi.mappings());
|
||||
}
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function configure() {
|
||||
return run((options) => grist.sectionApi.configure(...options));
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
document.getElementById('ready').innerText = 'ready';
|
||||
document.getElementById('access').innerHTML = urlParams.get('access');
|
||||
document.getElementById('readonly').innerHTML = urlParams.get('readonly');
|
||||
};
|
||||
16
test/fixtures/sites/embed/embed.html
vendored
Normal file
16
test/fixtures/sites/embed/embed.html
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
html, body { height: 100%; }
|
||||
#outside { display: block; height: 15%; width: 100%; }
|
||||
#embed { height: 70%; width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Embed Grist</h3>
|
||||
<textarea id='outside'></textarea>
|
||||
<iframe id='embed' src=""></iframe>
|
||||
</body>
|
||||
</html>
|
||||
12
test/fixtures/sites/filter/index.html
vendored
Normal file
12
test/fixtures/sites/filter/index.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Filter</h1>
|
||||
<p>Enter row ids (ie: "1" or "1, 3, 4"): </p>
|
||||
<input type="text" id="rowIds"/>
|
||||
</body>
|
||||
</html>
|
||||
13
test/fixtures/sites/filter/page.js
vendored
Normal file
13
test/fixtures/sites/filter/page.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
/* global document, grist, window */
|
||||
|
||||
function setup() {
|
||||
grist.ready();
|
||||
grist.allowSelectBy();
|
||||
document.querySelector('#rowIds').addEventListener('change', (ev) => {
|
||||
const rowIds = ev.target.value.split(',').map(Number);
|
||||
grist.setSelectedRows(rowIds);
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
5
test/fixtures/sites/hello/index.html
vendored
Normal file
5
test/fixtures/sites/hello/index.html
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1 id="hello-title">Hello World</h1>
|
||||
</body>
|
||||
</html>
|
||||
27
test/fixtures/sites/paste/paste.html
vendored
Normal file
27
test/fixtures/sites/paste/paste.html
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<body>
|
||||
<table cellspacing="0" cellpadding="0" border="1">
|
||||
<colgroup><col span="2"></colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>a</td>
|
||||
<td>b</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">c</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>d</td>
|
||||
<td rowspan="2">e</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>f</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
11
test/fixtures/sites/probe/index.html
vendored
Normal file
11
test/fixtures/sites/probe/index.html
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Probe</h1>
|
||||
<div id="placeholder"></div>
|
||||
</body>
|
||||
</html>
|
||||
20
test/fixtures/sites/probe/page.js
vendored
Normal file
20
test/fixtures/sites/probe/page.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
/* global document, grist, window */
|
||||
|
||||
grist.ready();
|
||||
|
||||
function readDoc() {
|
||||
const api = grist.rpc.getStub("GristDocAPI@grist", grist.checkers.GristDocAPI);
|
||||
const placeholder = document.getElementById('placeholder');
|
||||
const fallback = setTimeout(() => {
|
||||
placeholder.innerHTML = '<div id="output">no joy</div>';
|
||||
}, 1000);
|
||||
api.listTables()
|
||||
.then(tables => {
|
||||
clearTimeout(fallback);
|
||||
placeholder.innerHTML = `<div id="output">${JSON.stringify(tables)}</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = readDoc;
|
||||
21
test/fixtures/sites/readout/index.html
vendored
Normal file
21
test/fixtures/sites/readout/index.html
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Readout</h1>
|
||||
<h2>placeholder</h2>
|
||||
<div id="placeholder"></div>
|
||||
<h2>rowId</h2>
|
||||
<div id="rowId"></div>
|
||||
<h2>tableId</h2>
|
||||
<div id="tableId"></div>
|
||||
<hr />
|
||||
<h2>record</h2>
|
||||
<div id="record"></div>
|
||||
<h2>records</h2>
|
||||
<div id="records"></div>
|
||||
</body>
|
||||
</html>
|
||||
37
test/fixtures/sites/readout/page.js
vendored
Normal file
37
test/fixtures/sites/readout/page.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
|
||||
/* global document, grist, window */
|
||||
|
||||
function readDoc() {
|
||||
const fetchTable = grist.docApi.fetchSelectedTable();
|
||||
const placeholder = document.getElementById('placeholder');
|
||||
const fallback = setTimeout(() => {
|
||||
placeholder.innerHTML = '<div id="output">no joy</div>';
|
||||
}, 1000);
|
||||
fetchTable
|
||||
.then(table => {
|
||||
clearTimeout(fallback);
|
||||
placeholder.innerHTML = `<div id="output">${JSON.stringify(table)}</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
function setup() {
|
||||
grist.ready();
|
||||
grist.on('message', function(e) {
|
||||
if ('options' in e) return;
|
||||
document.getElementById('rowId').innerHTML = e.rowId || '';
|
||||
document.getElementById('tableId').innerHTML = e.tableId || '';
|
||||
readDoc();
|
||||
});
|
||||
grist.onRecord(function(rec) {
|
||||
document.getElementById('record').innerHTML = JSON.stringify(rec);
|
||||
});
|
||||
grist.onRecords(function(recs) {
|
||||
document.getElementById('records').innerHTML = JSON.stringify(recs);
|
||||
});
|
||||
grist.onNewRecord(function(rec) {
|
||||
document.getElementById('record').innerHTML = 'new';
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
16
test/fixtures/sites/types/index.html
vendored
Normal file
16
test/fixtures/sites/types/index.html
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Types</h1>
|
||||
<div>
|
||||
onRecord() matches a record in table?
|
||||
<div id="match"></div>
|
||||
</div>
|
||||
<h2>record</h2>
|
||||
<pre id="record"></pre>
|
||||
</body>
|
||||
</html>
|
||||
42
test/fixtures/sites/types/page.js
vendored
Normal file
42
test/fixtures/sites/types/page.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* global document, grist, window */
|
||||
|
||||
function formatValue(value, indent='') {
|
||||
let basic = `${value} [typeof=${typeof value}]`;
|
||||
if (value && typeof value === 'object') {
|
||||
basic += ` [name=${value.constructor.name}]`;
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
// For moment, use moment(value) or moment(value).tz(value.timezone), it's just hard to
|
||||
// include moment into this test fixture.
|
||||
basic += ` [date=${value.toISOString()}]`;
|
||||
}
|
||||
if (value && typeof value === 'object' && value.constructor.name === 'Object') {
|
||||
basic += "\n" + formatObject(value);
|
||||
}
|
||||
return basic;
|
||||
}
|
||||
|
||||
function formatObject(obj) {
|
||||
const keys = Object.keys(obj).sort();
|
||||
const rows = keys.map(k => `${k}: ${formatValue(obj[k])}`.replace(/\n/g, '\n '));
|
||||
return rows.join("\n");
|
||||
}
|
||||
|
||||
function setup() {
|
||||
let lastRecords = [];
|
||||
grist.ready();
|
||||
grist.onRecords(function(records) { lastRecords = records; });
|
||||
grist.onRecord(function(rec) {
|
||||
const formatted = formatObject(rec);
|
||||
document.getElementById('record').innerHTML = formatted;
|
||||
|
||||
// Check that there is an identical object in lastRecords, to ensure that onRecords() returns
|
||||
// the same kind of representation.
|
||||
const rowInRecords = lastRecords.find(r => (r.id === rec.id));
|
||||
const match = (formatObject(rowInRecords) === formatted);
|
||||
document.getElementById('match').textContent = String(match);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
11
test/fixtures/sites/zap/index.html
vendored
Normal file
11
test/fixtures/sites/zap/index.html
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="/grist-plugin-api.js"></script>
|
||||
<script src="page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Zap</h1>
|
||||
<div id="placeholder"></div>
|
||||
</body>
|
||||
</html>
|
||||
56
test/fixtures/sites/zap/page.js
vendored
Normal file
56
test/fixtures/sites/zap/page.js
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/* global document, grist, window */
|
||||
|
||||
/**
|
||||
* This widget connects to the document, gets a list of all user tables in it,
|
||||
* and then tries to replace all cells with the text 'zap'. It requires full
|
||||
* access to do this.
|
||||
*/
|
||||
|
||||
let failures = 0;
|
||||
function problem(err) {
|
||||
// Trying to zap formula columns will fail, but that's ok.
|
||||
if (String(err).includes("formula column")) { return; }
|
||||
console.error(err);
|
||||
document.getElementById('placeholder').innerHTML = 'zap failed';
|
||||
failures++;
|
||||
}
|
||||
|
||||
async function zap() {
|
||||
grist.ready();
|
||||
try {
|
||||
// If no access is granted, listTables will hang. Detect this condition with
|
||||
// a timeout.
|
||||
const timeout = setTimeout(() => problem(new Error('cannot connect')), 1000);
|
||||
const tables = await grist.docApi.listTables();
|
||||
clearTimeout(timeout);
|
||||
// Iterate through user tables.
|
||||
for (const tableId of tables) {
|
||||
// Read table content.
|
||||
const data = await grist.docApi.fetchTable(tableId);
|
||||
const ids = data.id;
|
||||
// Prepare to zap all columns except id and manualSort.
|
||||
delete data.id;
|
||||
delete data.manualSort;
|
||||
for (const key of Object.keys(data)) {
|
||||
const column = data[key];
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
column[i] = 'zap';
|
||||
}
|
||||
// Zap columns one by one since if they are a formula column they will fail.
|
||||
await grist.docApi.applyUserActions([[
|
||||
'BulkUpdateRecord',
|
||||
tableId,
|
||||
ids,
|
||||
{[key]: column},
|
||||
]]).catch(problem);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
problem(err);
|
||||
}
|
||||
if (failures === 0) {
|
||||
document.getElementById('placeholder').innerHTML = 'zap succeeded';
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = zap;
|
||||
Reference in New Issue
Block a user