blob: d07e5fd3d62694880bb3a69a6b4ca4ac1a9473e1 [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8">
<title>Toast: action tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<main></main>
<script type="module">
import { testActionToast, testToastElement, assertActionButtonOnToast } from './resources/helpers.js';
import { showToast } from 'std:elements/toast';
testActionToast((toast) => {
assert_equals(toast.action.textContent, 'action');
}, 'the action element gets properly captured with this.action');
testActionToast((toast) => {
toast.innerHTML = `<button slot='action'>new action</button>`
assert_equals(toast.action.textContent, 'new action');
}, 'changing the action button changes this.action');
testToastElement((toast) => {
assert_equals(toast.action, null);
}, 'the action property of a toast without an action is null');
testToastElement((toast) => {
toast.innerHTML = `<button slot="action" id="first">first</button>
<button slot="action" id="second">second</button>`;
assert_equals(toast.action, toast.querySelector('#first'));
}, 'toast action returns the first item with the action slot');
test(() => {
const toast = showToast('Message', {action: 'action'});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
}, 'passing an action via showToast creates a button');
test(() => {
const actionMarkup = '<b>strong text</b>';
const toast = showToast('Message', {action: actionMarkup});
const actionButton = toast.querySelector('button');
assert_equals(actionButton.textContent, actionMarkup);
assert_equals(toast.querySelector('b'), null);
}, 'passing markup to the action option represents as text');
test(() => {
const toast = document.createElement('std-toast');
toast.textContent = 'Message';
toast.show({action: 'action'});
const actionButton = toast.querySelector('button');
assert_equals(actionButton, null);
}, 'passing action option to show does not create a button');
test(() => {
const toast = showToast('Message', {action: null});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
assert_equals(actionButton.textContent, 'null');
}, 'passing non-string (null) as action option stringifies it and creates an action button');
test(() => {
const toast = showToast('Message', {action: false});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
assert_equals(actionButton.textContent, 'false');
}, 'passing non-string (false) as action option stringifies it and creates an action button');
test(() => {
const toast = showToast('Message', {action: 0});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
assert_equals(actionButton.textContent, '0');
}, 'passing non-string (0) as action option stringifies it and creates an action button');
test(() => {
const toast = showToast('Message', {action: 1});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
assert_equals(actionButton.textContent, '1');
}, 'passing non-string (1) as action option stringifies it and creates an action button');
test(() => {
const toast = showToast('Message', {action: {field: 'value'}});
const actionButton = toast.querySelector('button');
assertActionButtonOnToast(actionButton, toast);
assert_equals(actionButton.textContent, '[object Object]');
}, 'passing non-string ({field: value}) as action option stringifies it and creates an action button');
test(() => {
const toast = showToast('Message', {});
const actionButton = toast.querySelector('button');
assert_equals(actionButton, null);
}, 'passing non-string (undefined) as action option does not create an action button');
testToastElement((toast) => {
const actionButton = document.createElement('button');
actionButton.textContent = 'action';
toast.action = actionButton;
assertActionButtonOnToast(actionButton, toast);
}, 'setting the action on an actionless toast inserts the element into the slot');
testActionToast((toast, action) => {
const actionButton = document.createElement('button');
actionButton.textContent = 'replacement';
toast.action = actionButton;
assert_false(document.contains(action));
assertActionButtonOnToast(actionButton, toast);
}, 'resetting the action on an action toast changes the action element');
testToastElement((toast) => {
const text = document.createTextNode('some text');
assert_throws(new TypeError(), () => {
toast.action = text;
});
}, 'setting the action to an invalid type (Text node) throws an error');
testToastElement((toast) => {
const text = 'some text';
assert_throws(new TypeError(), () => {
toast.action = text;
});
}, 'setting the action to an invalid type (string) throws an error');
test(() => {
const actionButton = document.createElement('button');
actionButton.textContent = 'action';
const toast = showToast('Message', {action: actionButton});
assertActionButtonOnToast(actionButton, toast);
}, 'showToast can take an Element as the action parameter');
testActionToast((toast, action) => {
toast.action = null;
assert_not_equals(toast.action, action);
assert_equals(toast.querySelector('button'), null);
}, 'setting toast.action to null removes the action from the toast');
testActionToast((toast, action) => {
const wrongAction = document.createElement('button');
wrongAction.textContent = 'wrong';
wrongAction.setAttribute('slot', 'action');
toast.appendChild(wrongAction);
const correctAction = document.createElement('button');
correctAction.textContent = 'correct';
toast.action = correctAction;
assertActionButtonOnToast(correctAction, toast);
}, 'resetting toast.action on a toast with multiple actions slotted sets properly');
test(() => {
try {
Object.defineProperty(Element, Symbol.hasInstance, {
value: () => true,
configurable: true
});
const fakeElement = {};
const toast = showToast('Message');
assert_throws(new TypeError(), () => toast.action = fakeElement);
} finally {
delete Element[Symbol.hasInstance];
}
}, 'spoofing element instance will not register as element to action setter');
test(() => {
const iframe = document.createElement('iframe');
document.body.append(iframe);
iframe.contentDocument.body.innerHTML = '<div></div>';
const elementFromAnotherFrame = iframe.contentDocument.querySelector('div');
// Should not throw:
const toast = showToast('Message');
toast.action = elementFromAnotherFrame;
}, 'element from iframe instance will pass correctly to action without throwing an error');
</script>