mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
Add more unit tests for PyButton and BaseEvalElement (#711)
* Add more unit tests * Rebase main and fix failing tests * xfail flaky test * Fix import
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -136,3 +136,5 @@ dmypy.json
|
||||
.pyre/
|
||||
|
||||
node_modules/
|
||||
|
||||
coverage/
|
||||
|
||||
@@ -169,6 +169,9 @@ class TestExamples(PyScriptTest):
|
||||
assert self.page.title() == "PyScript/Panel Streaming Demo"
|
||||
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="Test seems flaky, sometimes it doesn't return result from second repl"
|
||||
)
|
||||
def test_repl(self):
|
||||
self.goto("examples/repl.html")
|
||||
self.wait_for_pyscript()
|
||||
|
||||
94
pyscriptjs/tests/unit/base.test.ts
Normal file
94
pyscriptjs/tests/unit/base.test.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
import { BaseEvalElement } from '../../src/components/base';
|
||||
import { runtimeLoaded } from '../../src/stores';
|
||||
|
||||
customElements.define('py-base', BaseEvalElement);
|
||||
|
||||
describe('BaseEvalElement', () => {
|
||||
let instance: BaseEvalElement;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new BaseEvalElement();
|
||||
});
|
||||
|
||||
it('BaseEvalElement instantiates correctly', async () => {
|
||||
expect(instance).toBeInstanceOf(BaseEvalElement);
|
||||
});
|
||||
|
||||
// TODO: This test is a bit silly, but the idea is to keep it here until we fix this
|
||||
// issue
|
||||
it("should fail with: Cannot use 'in' operator to search for 'runPythonAsync' in undefined", async () => {
|
||||
let thrownError;
|
||||
let expectedTypeError = new TypeError("Cannot use 'in' operator to search for 'run' in undefined");
|
||||
try {
|
||||
instance.runAfterRuntimeInitialized(async () => {
|
||||
return;
|
||||
});
|
||||
} catch (error) {
|
||||
thrownError = error;
|
||||
}
|
||||
expect(thrownError).toEqual(expectedTypeError);
|
||||
});
|
||||
|
||||
it('runAfterRuntimeInitialized calls runtimeLoaded.subscribe', async () => {
|
||||
const mockedStore = jest.fn();
|
||||
// @ts-ignore: typescript causes the test to fail
|
||||
const mockedruntimeLoaded = jest.spyOn(runtimeLoaded, 'subscribe').mockImplementation(mockedStore);
|
||||
|
||||
instance.runAfterRuntimeInitialized(async () => {});
|
||||
|
||||
expect(mockedruntimeLoaded).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('addToOutput sets outputElements property correctly', async () => {
|
||||
instance.outputElement = document.createElement('body');
|
||||
instance.addToOutput('Hello, world!');
|
||||
|
||||
expect(instance.outputElement.innerHTML).toBe('<div>Hello, world!</div>');
|
||||
expect(instance.outputElement.hidden).toBe(false);
|
||||
|
||||
instance.addToOutput('Have a good day!');
|
||||
expect(instance.outputElement.innerHTML).toBe('<div>Hello, world!</div><div>Have a good day!</div>');
|
||||
});
|
||||
|
||||
it('setOutputMode updates appendOutput property correctly', async () => {
|
||||
// Confirm that the default mode is 'append'
|
||||
expect(instance.appendOutput).toBe(true);
|
||||
|
||||
instance.setAttribute('output-mode', 'replace');
|
||||
instance.setOutputMode();
|
||||
|
||||
expect(instance.appendOutput).toBe(false);
|
||||
|
||||
// Using a custom output-mode shouldn't update mode
|
||||
instance.setAttribute('output-mode', 'custom');
|
||||
instance.setOutputMode();
|
||||
expect(instance.appendOutput).toBe(false);
|
||||
});
|
||||
|
||||
it('preEvaluate returns null since subclasses should overwrite it', async () => {
|
||||
const preEvaluateResult = instance.preEvaluate();
|
||||
expect(preEvaluateResult).toBeNull();
|
||||
});
|
||||
|
||||
it('postEvaluate returns null since subclasses should overwrite it', async () => {
|
||||
const preEvaluateResult = instance.postEvaluate();
|
||||
expect(preEvaluateResult).toBeNull();
|
||||
});
|
||||
|
||||
it('checkId generates id if none exists', async () => {
|
||||
// Test default value
|
||||
expect(instance.id).toBe('');
|
||||
|
||||
instance.checkId();
|
||||
|
||||
// expect id is similar to py-78c3e696-a74f-df40-f82c-535f12c484ae
|
||||
expect(instance.id).toMatch(/py-(\w+-){1,4}\w+/);
|
||||
});
|
||||
|
||||
it('getSourceFromElement returns empty string', async () => {
|
||||
const returnedGetSourceFromElement = instance.getSourceFromElement();
|
||||
expect(returnedGetSourceFromElement).toBe('');
|
||||
});
|
||||
});
|
||||
75
pyscriptjs/tests/unit/pybutton.test.ts
Normal file
75
pyscriptjs/tests/unit/pybutton.test.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { PyButton } from '../../src/components/pybutton';
|
||||
|
||||
customElements.define('py-button', PyButton);
|
||||
|
||||
describe('PyButton', () => {
|
||||
let instance: PyButton;
|
||||
beforeEach(() => {
|
||||
instance = new PyButton();
|
||||
instance.runAfterRuntimeInitialized = jest.fn();
|
||||
});
|
||||
|
||||
it('should get the Button to just instantiate', async () => {
|
||||
expect(instance).toBeInstanceOf(PyButton);
|
||||
});
|
||||
|
||||
it('confirm that runAfterRuntimeInitialized is called', async () => {
|
||||
const mockedRunAfterRuntimeInitialized = jest
|
||||
.spyOn(instance, 'runAfterRuntimeInitialized')
|
||||
.mockImplementation(jest.fn());
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(mockedRunAfterRuntimeInitialized).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('onCallback gets or sets a new id', async () => {
|
||||
expect(instance.id).toBe('');
|
||||
|
||||
instance.connectedCallback();
|
||||
const instanceId = instance.id;
|
||||
// id should be similar to py-4850c8c3-d70d-d9e0-03c1-3cfeb0bcec0d-container
|
||||
expect(instanceId).toMatch(/py-(\w+-){1,5}container/);
|
||||
|
||||
// calling checkId directly should return the same id
|
||||
instance.checkId();
|
||||
expect(instance.id).toEqual(instanceId);
|
||||
});
|
||||
|
||||
it('onCallback updates on_click code and function name ', async () => {
|
||||
expect(instance.code).toBe(undefined);
|
||||
expect(instance.innerHTML).toBe('');
|
||||
|
||||
instance.innerHTML = '\ndef on_click(e):\n';
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.code).toMatch(/def\son_click_py_(\w+)\(e\)/);
|
||||
expect(instance.innerHTML).toContain('<button class="py-button"');
|
||||
});
|
||||
|
||||
it('onCallback updates on_focus code and function name', async () => {
|
||||
expect(instance.code).toBe(undefined);
|
||||
expect(instance.innerHTML).toBe('');
|
||||
|
||||
instance.innerHTML = '\ndef on_focus(e):\n';
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.code).toMatch(/def\son_focus_py_(\w+)\(e\)/);
|
||||
expect(instance.innerHTML).toContain('<button class="py-button"');
|
||||
});
|
||||
|
||||
it('onCallback sets mount_name based on id', async () => {
|
||||
expect(instance.id).toBe('');
|
||||
expect(instance.mount_name).toBe(undefined);
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
const instanceId = instance.id;
|
||||
|
||||
expect(instanceId).toMatch(/py-(\w+-){1,5}container/);
|
||||
expect(instance.mount_name).toBe(instanceId.replace('-container', '').split('-').join('_'));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user