mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
Add more unit and integration tests (#773)
* Add unit tests for pyloader and pytitle * Add more unit tests for pyrepl, pybox and pyinputbox * Add more tests for pyscript and pyconfig * White space * Fix d3 tests and improve more examples test * Update matplotlib test * Add numpy to dependencies * Address Madhur comments * Update test name
This commit is contained in:
@@ -11,6 +11,8 @@ dependencies:
|
||||
- isort
|
||||
- codespell
|
||||
- pre-commit
|
||||
- pillow
|
||||
- numpy
|
||||
|
||||
- pip:
|
||||
- playwright
|
||||
|
||||
BIN
pyscriptjs/tests/integration/test_assets/tripcolor.png
Normal file
BIN
pyscriptjs/tests/integration/test_assets/tripcolor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -1,8 +1,13 @@
|
||||
import base64
|
||||
import io
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .support import ROOT, PyScriptTest
|
||||
|
||||
@@ -80,7 +85,6 @@ class TestExamples(PyScriptTest):
|
||||
wait_for_render(self.page, "*", '<canvas.*?class=\\"marks\\".*?>')
|
||||
save_as_png_link = self.page.locator("text=Save as PNG")
|
||||
see_source_link = self.page.locator("text=View Source")
|
||||
|
||||
# These shouldn't be visible since we didn't click the menu
|
||||
assert not save_as_png_link.is_visible()
|
||||
assert not see_source_link.is_visible()
|
||||
@@ -105,32 +109,66 @@ class TestExamples(PyScriptTest):
|
||||
assert self.page.title() == "Bokeh Example"
|
||||
wait_for_render(self.page, "*", '<div.*?class=\\"bk\\".*?>')
|
||||
|
||||
@pytest.mark.xfail(reason="Flaky test #759")
|
||||
def test_d3(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/d3.html")
|
||||
self.wait_for_pyscript()
|
||||
assert (
|
||||
self.page.title() == "d3: JavaScript & PyScript visualizations side-by-side"
|
||||
)
|
||||
wait_for_render(self.page, "*", "<svg.*?>")
|
||||
assert "PyScript version" in self.page.content()
|
||||
pyscript_chart = self.page.wait_for_selector("#py")
|
||||
|
||||
# Let's simply assert that the text of the chart is as expected which
|
||||
# means that the chart rendered successfully and with the right text
|
||||
assert "🍊21\n🍇13\n🍏8\n🍌5\n🍐3\n🍋2\n🍎1\n🍉1" in pyscript_chart.inner_text()
|
||||
|
||||
def test_folium(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/folium.html")
|
||||
self.wait_for_pyscript()
|
||||
assert self.page.title() == "Folium"
|
||||
wait_for_render(self.page, "*", "<iframe srcdoc=")
|
||||
|
||||
# We need to look into the iframe first
|
||||
iframe = self.page.frame_locator("iframe")
|
||||
|
||||
# Just checking that legend was rendered correctly
|
||||
legend = iframe.locator("#legend")
|
||||
assert "Unemployment Rate (%)" in legend.inner_html()
|
||||
|
||||
# Let's check that the zoom buttons are rendered and clickable
|
||||
# Note: if element is not clickable it will timeout
|
||||
zoom_in = iframe.locator("[aria-label='Zoom in']")
|
||||
assert "+" in zoom_in.inner_text()
|
||||
zoom_in.click()
|
||||
zoom_out = iframe.locator("[aria-label='Zoom out']")
|
||||
assert "−" in zoom_out.inner_text()
|
||||
zoom_out.click()
|
||||
|
||||
def test_matplotlib(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/matplotlib.html")
|
||||
self.wait_for_pyscript()
|
||||
assert self.page.title() == "Matplotlib"
|
||||
wait_for_render(self.page, "*", "<img src=['\"]data:image")
|
||||
# The image is being rended using base64, lets fetch its source
|
||||
# and replace everything but the actual base64 string.\
|
||||
img_src = (
|
||||
self.page.wait_for_selector("img")
|
||||
.get_attribute("src")
|
||||
.replace("data:image/png;charset=utf-8;base64,", "")
|
||||
)
|
||||
# Finally, let's get the np array from the previous data
|
||||
img_data = np.asarray(Image.open(io.BytesIO(base64.b64decode(img_src))))
|
||||
with Image.open(
|
||||
os.path.join(os.path.dirname(__file__), "test_assets", "tripcolor.png"),
|
||||
) as image:
|
||||
ref_data = np.asarray(image)
|
||||
# Now that we have both images data as a numpy array
|
||||
# let's confirm that they are the same
|
||||
deviation = np.mean(np.abs(img_data - ref_data))
|
||||
assert deviation == 0.0
|
||||
|
||||
def test_numpy_canvas_fractals(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/numpy_canvas_fractals.html")
|
||||
self.wait_for_pyscript()
|
||||
assert (
|
||||
@@ -141,12 +179,57 @@ class TestExamples(PyScriptTest):
|
||||
self.page, "*", "<div.*?id=['\"](mandelbrot|julia|newton)['\"].*?>"
|
||||
)
|
||||
|
||||
# Assert that we get the title and canvas for each element
|
||||
mandelbrot = self.page.wait_for_selector("#mandelbrot")
|
||||
assert "Mandelbrot set" in mandelbrot.inner_text()
|
||||
assert "<canvas" in mandelbrot.inner_html()
|
||||
|
||||
julia = self.page.wait_for_selector("#julia")
|
||||
assert "Julia set" in julia.inner_text()
|
||||
assert "<canvas" in julia.inner_html()
|
||||
|
||||
newton = self.page.wait_for_selector("#newton")
|
||||
assert "Newton set" in newton.inner_text()
|
||||
assert "<canvas" in newton.inner_html()
|
||||
|
||||
# Confirm that all fieldsets are rendered correctly
|
||||
poly = newton.wait_for_selector("#poly")
|
||||
assert poly.input_value() == "z**3 - 2*z + 2"
|
||||
|
||||
coef = newton.wait_for_selector("#coef")
|
||||
assert coef.input_value() == "1"
|
||||
|
||||
# Let's now change some x/y values to confirm that they
|
||||
# are editable (is it the best way to test this?)
|
||||
x0 = newton.wait_for_selector("#x0")
|
||||
y0 = newton.wait_for_selector("#y0")
|
||||
|
||||
x0.fill("50")
|
||||
assert x0.input_value() == "50"
|
||||
y0.fill("-25")
|
||||
assert y0.input_value() == "-25"
|
||||
|
||||
# This was the first computation with the default values
|
||||
assert self.console.log.lines[-2] == "Computing Newton set ..."
|
||||
# Confirm that changing the input values, triggered a new computation
|
||||
assert self.console.log.lines[-1] == "Computing Newton set ..."
|
||||
|
||||
def test_panel(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/panel.html")
|
||||
self.wait_for_pyscript()
|
||||
assert self.page.title() == "Panel Example"
|
||||
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
||||
slider_title = self.page.wait_for_selector(".bk-slider-title")
|
||||
assert slider_title.inner_text() == "Amplitude: 0"
|
||||
|
||||
slider_result = self.page.wait_for_selector(".bk-clearfix")
|
||||
assert slider_result.inner_text() == "Amplitude is: 0"
|
||||
|
||||
amplitude_bar = self.page.wait_for_selector(".noUi-connects")
|
||||
amplitude_bar.click()
|
||||
|
||||
# Let's confirm that slider title changed
|
||||
assert slider_title.inner_text() == "Amplitude: 5"
|
||||
|
||||
def test_panel_deckgl(self):
|
||||
# XXX improve this test
|
||||
@@ -190,7 +273,6 @@ class TestExamples(PyScriptTest):
|
||||
)
|
||||
assert second_repl_result.text_content() == "4"
|
||||
|
||||
@pytest.mark.xfail(reason="Test seems flaky")
|
||||
def test_repl2(self):
|
||||
self.goto("examples/repl2.html")
|
||||
self.wait_for_pyscript()
|
||||
|
||||
25
pyscriptjs/tests/unit/pybox.test.ts
Normal file
25
pyscriptjs/tests/unit/pybox.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { jest } from "@jest/globals"
|
||||
|
||||
import { PyBox } from "../../src/components/pybox"
|
||||
|
||||
customElements.define('py-box', PyBox)
|
||||
|
||||
describe('PyBox', () => {
|
||||
let instance: PyBox;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyBox();
|
||||
})
|
||||
|
||||
it('PyBox instantiates correctly', async () => {
|
||||
expect(instance).toBeInstanceOf(PyBox)
|
||||
})
|
||||
|
||||
it("test connectedCallback creates pybox div", async () => {
|
||||
expect(instance.innerHTML).toBe("")
|
||||
instance.connectedCallback()
|
||||
|
||||
expect(instance.innerHTML).toBe('<div class=\"py-box\"></div>')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -14,7 +14,7 @@ describe('PyButton', () => {
|
||||
expect(instance).toBeInstanceOf(PyButton);
|
||||
});
|
||||
|
||||
it('confirm that runAfterRuntimeInitialized is called', async () => {
|
||||
it('confirm that runAfterRuntimeInitialized is called', async () => {
|
||||
const mockedRunAfterRuntimeInitialized = jest
|
||||
.spyOn(instance, 'runAfterRuntimeInitialized')
|
||||
.mockImplementation(jest.fn());
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import type { AppConfig, RuntimeConfig } from '../../src/runtime';
|
||||
import { PyConfig } from '../../src/components/pyconfig';
|
||||
// inspired by trump typos
|
||||
const covfefeConfig = {
|
||||
"name": "covfefe",
|
||||
"runtimes": [{
|
||||
"src": "/demo/covfefe.js",
|
||||
"name": "covfefe",
|
||||
"lang": "covfefe"
|
||||
}],
|
||||
"wonerful": "discgrace"
|
||||
name: 'covfefe',
|
||||
runtimes: [
|
||||
{
|
||||
src: '/demo/covfefe.js',
|
||||
name: 'covfefe',
|
||||
lang: 'covfefe',
|
||||
},
|
||||
],
|
||||
wonerful: 'discgrace',
|
||||
};
|
||||
|
||||
const covfefeConfigToml = `
|
||||
@@ -21,20 +25,18 @@ name = "covfefe"
|
||||
lang = "covfefe"
|
||||
`;
|
||||
|
||||
import {jest} from '@jest/globals';
|
||||
|
||||
customElements.define('py-config', PyConfig);
|
||||
|
||||
describe('PyConfig', () => {
|
||||
let instance: PyConfig;
|
||||
|
||||
const xhrMockClass = () => ({
|
||||
open : jest.fn(),
|
||||
send : jest.fn(),
|
||||
responseText : JSON.stringify(covfefeConfig)
|
||||
open: jest.fn(),
|
||||
send: jest.fn(),
|
||||
responseText: JSON.stringify(covfefeConfig),
|
||||
});
|
||||
// @ts-ignore
|
||||
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass)
|
||||
window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyConfig();
|
||||
@@ -47,57 +49,57 @@ describe('PyConfig', () => {
|
||||
it('should load runtime from config and set as script src', () => {
|
||||
instance.values = covfefeConfig;
|
||||
instance.loadRuntimes();
|
||||
expect(document.scripts[0].src).toBe("http://localhost/demo/covfefe.js");
|
||||
expect(document.scripts[0].src).toBe('http://localhost/demo/covfefe.js');
|
||||
});
|
||||
|
||||
it('should load the default config', ()=> {
|
||||
it('should load the default config', () => {
|
||||
instance.connectedCallback();
|
||||
expect(instance.values.name).toBe("pyscript");
|
||||
expect(instance.values.author_email).toBe("foo@bar.com");
|
||||
expect(instance.values.name).toBe('pyscript');
|
||||
expect(instance.values.author_email).toBe('foo@bar.com');
|
||||
expect(instance.values.pyscript?.time).not.toBeNull();
|
||||
// @ts-ignore
|
||||
expect(instance.values.runtimes[0].lang).toBe("python");
|
||||
expect(instance.values.runtimes[0].lang).toBe('python');
|
||||
});
|
||||
|
||||
it('should load the JSON config from inline', ()=> {
|
||||
instance.setAttribute("type", "json");
|
||||
it('should load the JSON config from inline', () => {
|
||||
instance.setAttribute('type', 'json');
|
||||
instance.innerHTML = JSON.stringify(covfefeConfig);
|
||||
instance.connectedCallback();
|
||||
// @ts-ignore
|
||||
expect(instance.values.runtimes[0].lang).toBe("covfefe");
|
||||
expect(instance.values.runtimes[0].lang).toBe('covfefe');
|
||||
expect(instance.values.pyscript?.time).not.toBeNull();
|
||||
// version wasn't present in `inline config` but is still set due to merging with default
|
||||
expect(instance.values.version).toBe("0.1");
|
||||
expect(instance.values.version).toBe('0.1');
|
||||
});
|
||||
|
||||
it('should load the JSON config from src attribute', ()=> {
|
||||
instance.setAttribute("type", "json");
|
||||
instance.setAttribute("src", "/covfefe.json");
|
||||
it('should load the JSON config from src attribute', () => {
|
||||
instance.setAttribute('type', 'json');
|
||||
instance.setAttribute('src', '/covfefe.json');
|
||||
instance.connectedCallback();
|
||||
// @ts-ignore
|
||||
expect(instance.values.runtimes[0].lang).toBe("covfefe");
|
||||
expect(instance.values.runtimes[0].lang).toBe('covfefe');
|
||||
expect(instance.values.pyscript?.time).not.toBeNull();
|
||||
// wonerful is an extra key supplied by the user and is unaffected by merging process
|
||||
expect(instance.values.wonerful).toBe("discgrace");
|
||||
expect(instance.values.wonerful).toBe('discgrace');
|
||||
// version wasn't present in `config from src` but is still set due to merging with default
|
||||
expect(instance.values.version).toBe("0.1");
|
||||
expect(instance.values.version).toBe('0.1');
|
||||
});
|
||||
|
||||
it('should load the JSON config from both inline and src', ()=> {
|
||||
instance.setAttribute("type", "json");
|
||||
instance.innerHTML = JSON.stringify({"version": "0.2a", "wonerful": "highjacked"});
|
||||
instance.setAttribute("src", "/covfefe.json");
|
||||
it('should load the JSON config from both inline and src', () => {
|
||||
instance.setAttribute('type', 'json');
|
||||
instance.innerHTML = JSON.stringify({ version: '0.2a', wonerful: 'highjacked' });
|
||||
instance.setAttribute('src', '/covfefe.json');
|
||||
instance.connectedCallback();
|
||||
// @ts-ignore
|
||||
expect(instance.values.runtimes[0].lang).toBe("covfefe");
|
||||
expect(instance.values.runtimes[0].lang).toBe('covfefe');
|
||||
expect(instance.values.pyscript?.time).not.toBeNull();
|
||||
// config from src had an extra key "wonerful" with value "discgrace"
|
||||
// inline config had the same extra key "wonerful" with value "highjacked"
|
||||
// the merge process works for extra keys that clash as well
|
||||
// so the final value is "highjacked" since inline takes precedence over src
|
||||
expect(instance.values.wonerful).toBe("highjacked");
|
||||
expect(instance.values.wonerful).toBe('highjacked');
|
||||
// version wasn't present in `config from src` but is still set due to merging with default and inline
|
||||
expect(instance.values.version).toBe("0.2a");
|
||||
expect(instance.values.version).toBe('0.2a');
|
||||
});
|
||||
|
||||
it('should be able to load an inline TOML config', () => {
|
||||
@@ -105,11 +107,11 @@ describe('PyConfig', () => {
|
||||
instance.innerHTML = covfefeConfigToml;
|
||||
instance.connectedCallback();
|
||||
// @ts-ignore
|
||||
expect(instance.values.runtimes[0].lang).toBe("covfefe");
|
||||
expect(instance.values.runtimes[0].lang).toBe('covfefe');
|
||||
expect(instance.values.pyscript?.time).not.toBeNull();
|
||||
// version wasn't present in `inline config` but is still set due to merging with default
|
||||
expect(instance.values.version).toBe("0.1");
|
||||
expect(instance.values.wonerful).toBe("highjacked");
|
||||
expect(instance.values.version).toBe('0.1');
|
||||
expect(instance.values.wonerful).toBe('highjacked');
|
||||
});
|
||||
|
||||
it.failing('should NOT be able to load an inline config in JSON format with type as TOML', () => {
|
||||
@@ -118,21 +120,56 @@ describe('PyConfig', () => {
|
||||
});
|
||||
|
||||
it.failing('should NOT be able to load an inline config in TOML format with type as JSON', () => {
|
||||
instance.setAttribute("type", "json");
|
||||
instance.setAttribute('type', 'json');
|
||||
instance.innerHTML = covfefeConfigToml;
|
||||
instance.connectedCallback();
|
||||
});
|
||||
|
||||
it.failing('should NOT be able to load an inline TOML config with a JSON config from src with type as toml', () => {
|
||||
instance.innerHTML = covfefeConfigToml;
|
||||
instance.setAttribute("src", "/covfefe.json");
|
||||
instance.setAttribute('src', '/covfefe.json');
|
||||
instance.connectedCallback();
|
||||
});
|
||||
|
||||
it.failing('should NOT be able to load an inline TOML config with a JSON config from src with type as json', () => {
|
||||
instance.setAttribute("type", "json");
|
||||
instance.setAttribute('type', 'json');
|
||||
instance.innerHTML = covfefeConfigToml;
|
||||
instance.setAttribute("src", "/covfefe.json");
|
||||
instance.setAttribute('src', '/covfefe.json');
|
||||
instance.connectedCallback();
|
||||
});
|
||||
|
||||
it('connectedCallback should call loadRuntimes', async () => {
|
||||
const mockedMethod = jest.fn();
|
||||
instance.loadRuntimes = mockedMethod;
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(mockedMethod).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('confirm connectedCallback happy path', async () => {
|
||||
const mockedMethod = jest.fn();
|
||||
instance.loadRuntimes = mockedMethod;
|
||||
instance.innerHTML = 'test';
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.code).toBe('test');
|
||||
expect(instance.values['0']).toBe('test');
|
||||
});
|
||||
|
||||
it('log should add new message to the page', async () => {
|
||||
// details are undefined, so let's create a div for it
|
||||
instance.details = document.createElement('div');
|
||||
instance.log('this is a log');
|
||||
|
||||
// @ts-ignore: typescript complains about accessing innerText
|
||||
expect(instance.details.childNodes[0].innerText).toBe('this is a log');
|
||||
});
|
||||
|
||||
it('confirm that calling close would call this.remove', async () => {
|
||||
instance.remove = jest.fn();
|
||||
instance.close();
|
||||
expect(instance.remove).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
66
pyscriptjs/tests/unit/pyinputbox.test.ts
Normal file
66
pyscriptjs/tests/unit/pyinputbox.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { jest } from "@jest/globals"
|
||||
|
||||
import { PyInputBox } from "../../src/components/pyinputbox"
|
||||
|
||||
customElements.define('py-inputbox', PyInputBox)
|
||||
|
||||
describe("PyInputBox", () => {
|
||||
let instance: PyInputBox;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyInputBox()
|
||||
instance.runAfterRuntimeInitialized = jest.fn();
|
||||
})
|
||||
|
||||
it("PyInputBox instantiates correctly", async () => {
|
||||
expect(instance).toBeInstanceOf(PyInputBox)
|
||||
})
|
||||
|
||||
it('connectedCallback 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('confirm that runAfterRuntimeInitialized is called', async () => {
|
||||
const mockedRunAfterRuntimeInitialized = jest
|
||||
.spyOn(instance, 'runAfterRuntimeInitialized')
|
||||
.mockImplementation(jest.fn());
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(mockedRunAfterRuntimeInitialized).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
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('_'));
|
||||
});
|
||||
|
||||
it('onCallback updates on_keypress code and function name ', async () => {
|
||||
expect(instance.code).toBe(undefined);
|
||||
expect(instance.innerHTML).toBe('');
|
||||
|
||||
instance.innerHTML = '\ndef on_keypress(e):\n';
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.code).toMatch(/def\son_keypress_py_(\w+)\(e\)/);
|
||||
expect(instance.innerHTML).toContain('<input type="text" class="py-input"');
|
||||
});
|
||||
|
||||
})
|
||||
52
pyscriptjs/tests/unit/pyloader.test.ts
Normal file
52
pyscriptjs/tests/unit/pyloader.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import { PyLoader } from "../../src/components/pyloader"
|
||||
import { getLogger } from "../../src/logger"
|
||||
|
||||
customElements.define('py-loader', PyLoader);
|
||||
|
||||
describe('PyLoader', () => {
|
||||
let instance: PyLoader;
|
||||
const logger = getLogger("py-loader")
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyLoader();
|
||||
logger.info = jest.fn()
|
||||
})
|
||||
|
||||
it('PyLoader instantiates correctly', async () => {
|
||||
expect (instance).toBeInstanceOf(PyLoader);
|
||||
})
|
||||
|
||||
it('connectedCallback adds splash screen', async () => {
|
||||
// innerHTML should be empty
|
||||
expect(instance.innerHTML).toBe("")
|
||||
instance.connectedCallback();
|
||||
|
||||
// This is just checking that we have some ids or class names
|
||||
expect(instance.innerHTML).toContain('pyscript_loading_splash')
|
||||
expect(instance.innerHTML).toContain("spinner")
|
||||
|
||||
expect(instance.mount_name).toBe("")
|
||||
})
|
||||
|
||||
it('confirm calling log will log to console and page', () => {
|
||||
const element = document.createElement('div')
|
||||
element.setAttribute("id", "pyscript-operation-details")
|
||||
|
||||
instance.details = element
|
||||
instance.log("Hello, world!")
|
||||
|
||||
const printedLog = element.getElementsByTagName('p')
|
||||
|
||||
expect(logger.info).toHaveBeenCalledWith("Hello, world!")
|
||||
expect(printedLog[0].innerText).toBe("Hello, world!")
|
||||
})
|
||||
|
||||
it('confirm that calling close removes element', async () => {
|
||||
instance.remove = jest.fn()
|
||||
instance.close()
|
||||
expect(logger.info).toHaveBeenCalledWith("Closing")
|
||||
expect(instance.remove).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'jest';
|
||||
|
||||
import { PyRepl } from '../../src/components/pyrepl';
|
||||
|
||||
customElements.define('py-repl', PyRepl);
|
||||
@@ -13,4 +14,52 @@ describe('PyRepl', () => {
|
||||
expect(instance).toBeInstanceOf(PyRepl);
|
||||
});
|
||||
|
||||
it('confirm that codemirror editor is available', async () => {
|
||||
// We are assuming that if editorNode has the 'editor-box' class
|
||||
// then the div was created properly.
|
||||
expect(instance.editorNode.getAttribute('class')).toBe("editor-box")
|
||||
})
|
||||
|
||||
it("connectedCallback gets or sets new id", async () => {
|
||||
expect(instance.id).toBe("")
|
||||
|
||||
instance.connectedCallback()
|
||||
|
||||
const instanceId = instance.id;
|
||||
// id should be similar to py-4850c8c3-d70d-d9e0-03c1-3cfeb0bcec0d
|
||||
expect(instanceId).toMatch(/py-(\w+-){1,4}\w+/);
|
||||
|
||||
// calling checkId directly should return the same id
|
||||
instance.checkId();
|
||||
expect(instance.id).toEqual(instanceId);
|
||||
})
|
||||
|
||||
it('confirm that calling connectedCallback renders the expected elements', async () => {
|
||||
expect(instance.innerHTML).toBe("")
|
||||
instance.innerHTML = "<p>Hello</p>"
|
||||
instance.connectedCallback()
|
||||
|
||||
expect(instance.code).toBe("<p>Hello</p>")
|
||||
expect(instance.editorNode.id).toBe("code-editor")
|
||||
|
||||
// Just check that the button was created
|
||||
expect(instance.btnRun.getAttribute("class")).toBe("absolute repl-play-button")
|
||||
const editorNode = instance.editorNode.innerHTML
|
||||
expect(editorNode).toContain("Python Script Run Button")
|
||||
// Confirm that our innerHTML is set as well
|
||||
expect(editorNode).toContain("Hello")
|
||||
})
|
||||
|
||||
it("confirm that addToOutput updates output element", async () => {
|
||||
expect(instance.outputElement).toBe(undefined)
|
||||
|
||||
// This is just to avoid throwing the test since outputElement is undefined
|
||||
instance.outputElement = document.createElement("div")
|
||||
|
||||
instance.addToOutput("Hello, World!")
|
||||
|
||||
expect(instance.outputElement.innerHTML).toBe("<div>Hello, World!</div>")
|
||||
expect(instance.outputElement.hidden).toBe(false)
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
76
pyscriptjs/tests/unit/pyscript.test.ts
Normal file
76
pyscriptjs/tests/unit/pyscript.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { jest } from "@jest/globals"
|
||||
|
||||
import { PyScript } from "../../src/components/pyscript"
|
||||
|
||||
customElements.define('py-script', PyScript)
|
||||
|
||||
describe('PyScript', () => {
|
||||
let instance: PyScript;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyScript();
|
||||
})
|
||||
|
||||
it('PyScript instantiates correctly', async () => {
|
||||
expect(instance).toBeInstanceOf(PyScript)
|
||||
})
|
||||
|
||||
it('connectedCallback 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}/);
|
||||
|
||||
// calling checkId directly should return the same id
|
||||
instance.checkId();
|
||||
expect(instance.id).toEqual(instanceId);
|
||||
});
|
||||
|
||||
it('connectedCallback creates output div', async () => {
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.innerHTML).toContain('<div class="output">')
|
||||
})
|
||||
|
||||
it('confirm that outputElement has std-out id element', async () => {
|
||||
expect(instance.outputElement).toBe(undefined);
|
||||
|
||||
instance.setAttribute('id', 'std-out')
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.outputElement.getAttribute('id')).toBe("std-out")
|
||||
})
|
||||
|
||||
it('confirm that std-err id element sets errorElement', async () => {
|
||||
expect(instance.outputElement).toBe(undefined);
|
||||
|
||||
instance.setAttribute('id', 'std-err')
|
||||
instance.connectedCallback();
|
||||
|
||||
// We should have an errorElement
|
||||
expect(instance.errorElement.getAttribute('id')).toBe("std-err")
|
||||
})
|
||||
|
||||
it('test output attribute path', async () => {
|
||||
expect(instance.outputElement).toBe(undefined);
|
||||
expect(instance.errorElement).toBe(undefined)
|
||||
|
||||
const createdOutput = document.createElement("output")
|
||||
|
||||
instance.setAttribute('output', 'output')
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.innerHTML).toBe('<div class="output"></div>')
|
||||
})
|
||||
|
||||
it('getSourceFromElement returns decoded html', async () => {
|
||||
instance.innerHTML = "<p>Hello</p>"
|
||||
|
||||
instance.connectedCallback();
|
||||
const source = instance.getSourceFromElement();
|
||||
|
||||
expect(source).toBe("<p>Hello</p>")
|
||||
})
|
||||
})
|
||||
40
pyscriptjs/tests/unit/pytitle.test.ts
Normal file
40
pyscriptjs/tests/unit/pytitle.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { jest } from "@jest/globals";
|
||||
|
||||
import { PyTitle } from "../../src/components/pytitle"
|
||||
|
||||
|
||||
customElements.define("py-title", PyTitle);
|
||||
|
||||
|
||||
describe("PyTitle", () => {
|
||||
let instance: PyTitle;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new PyTitle();
|
||||
})
|
||||
|
||||
it("PyTitle instantiates correctly", async () => {
|
||||
expect(instance).toBeInstanceOf(PyTitle);
|
||||
})
|
||||
|
||||
it("test connectedCallback defaults", async () => {
|
||||
instance.connectedCallback();
|
||||
expect(instance.label).toBe("")
|
||||
expect(instance.mount_name).toBe("")
|
||||
expect(instance.innerHTML).toBe(`<div class=\"py-title\" id=\"\"><h1></h1></div>`)
|
||||
})
|
||||
|
||||
it("label renders correctly on the page and updates id", async () => {
|
||||
instance.innerHTML = "Hello, world!"
|
||||
// We need this to test mount_name works properly since connectedCallback
|
||||
// doesn't automatically call checkId (should it?)
|
||||
instance.checkId();
|
||||
|
||||
instance.connectedCallback();
|
||||
|
||||
expect(instance.label).toBe("Hello, world!")
|
||||
// mount_name should be similar to: py_be025f4c_2150_7f2a_1a85_af92970c2a0e
|
||||
expect(instance.mount_name).toMatch(/py_(\w+_){1,5}/);
|
||||
expect(instance.innerHTML).toContain("<h1>Hello, world!</h1>")
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user