Skip to content

Commit

Permalink
Merge pull request #7393 from limzykenneth/2.0-unit-tests
Browse files Browse the repository at this point in the history
[p5.js 2.0] Unit tests fix/conversion
  • Loading branch information
limzykenneth authored Dec 3, 2024
2 parents bc5db33 + ddc5284 commit 7af092f
Show file tree
Hide file tree
Showing 18 changed files with 1,109 additions and 1,595 deletions.
64 changes: 61 additions & 3 deletions src/dom/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ function dom(p5, fn){
let container = document;
if (typeof p === 'string') {
container = document.querySelector(p) || document;
} else if (p instanceof p5.Element) {
} else if (p instanceof Element) {
container = p.elt;
} else if (p instanceof HTMLElement) {
container = p;
Expand Down Expand Up @@ -256,6 +256,64 @@ function dom(p5, fn){
}
};

/**
* Creates a new <a href="#/p5.Element">p5.Element</a> object.
*
* The first parameter, `tag`, is a string an HTML tag such as `'h5'`.
*
* The second parameter, `content`, is optional. It's a string that sets the
* HTML content to insert into the new element. New elements have no content
* by default.
*
* @method createElement
* @param {String} tag tag for the new element.
* @param {String} [content] HTML content to insert into the element.
* @return {p5.Element} new <a href="#/p5.Element">p5.Element</a> object.
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create an h5 element with nothing in it.
* createElement('h5');
*
* describe('A gray square.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create an h5 element with the content "p5*js".
* let h5 = createElement('h5', 'p5*js');
*
* // Set the element's style and position.
* h5.style('color', 'deeppink');
* h5.position(30, 15);
*
* describe('The text "p5*js" written in pink in the middle of a gray square.');
* }
* </code>
* </div>
*/
fn.createElement = function (tag, content) {
p5._validateParameters('createElement', arguments);
const elt = document.createElement(tag);
if (typeof content !== 'undefined') {
elt.innerHTML = content;
}
return addElement(elt, this);
};

/**
* Removes all elements created by p5.js, including any event handlers.
*
Expand Down Expand Up @@ -1186,7 +1244,7 @@ function dom(p5, fn){
p5._validateParameters('createSelect', args);
let self;
let arg = args[0];
if (arg instanceof p5.Element && arg.elt instanceof HTMLSelectElement) {
if (arg instanceof Element && arg.elt instanceof HTMLSelectElement) {
// If given argument is p5.Element of select type
self = arg;
this.elt = arg.elt;
Expand Down Expand Up @@ -1444,7 +1502,7 @@ function dom(p5, fn){
let name;
const arg0 = args[0];
if (
arg0 instanceof p5.Element &&
arg0 instanceof Element &&
(arg0.elt instanceof HTMLDivElement || arg0.elt instanceof HTMLSpanElement)
) {
// If given argument is p5.Element of div/span type
Expand Down
59 changes: 0 additions & 59 deletions src/dom/p5.MediaElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -1744,65 +1744,6 @@ function media(p5, fn){
return videoEl;
};


/**
* Creates a new <a href="#/p5.Element">p5.Element</a> object.
*
* The first parameter, `tag`, is a string an HTML tag such as `'h5'`.
*
* The second parameter, `content`, is optional. It's a string that sets the
* HTML content to insert into the new element. New elements have no content
* by default.
*
* @method createElement
* @param {String} tag tag for the new element.
* @param {String} [content] HTML content to insert into the element.
* @return {p5.Element} new <a href="#/p5.Element">p5.Element</a> object.
*
* @example
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create an h5 element with nothing in it.
* createElement('h5');
*
* describe('A gray square.');
* }
* </code>
* </div>
*
* <div>
* <code>
* function setup() {
* createCanvas(100, 100);
*
* background(200);
*
* // Create an h5 element with the content "p5*js".
* let h5 = createElement('h5', 'p5*js');
*
* // Set the element's style and position.
* h5.style('color', 'deeppink');
* h5.position(30, 15);
*
* describe('The text "p5*js" written in pink in the middle of a gray square.');
* }
* </code>
* </div>
*/
fn.createElement = function (tag, content) {
p5._validateParameters('createElement', arguments);
const elt = document.createElement(tag);
if (typeof content !== 'undefined') {
elt.innerHTML = content;
}
return addElement(elt, this);
};

// =============================================================================
// p5.MediaElement additions
// =============================================================================
Expand Down
14 changes: 11 additions & 3 deletions test/js/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,25 @@ const httpMocks = [
export const httpMock = setupWorker(...httpMocks);

// p5.js module mocks
export const mockP5 = {
export const mockP5 = vi.fn();
Object.assign(mockP5, {
_validateParameters: vi.fn(),
_friendlyFileLoadError: vi.fn(),
_friendlyError: vi.fn()
};
});

const mockCanvas = document.createElement('canvas');
mockCanvas.id = 'myCanvasID';
document.getElementsByTagName("body")[0].appendChild(mockCanvas);

export const mockP5Prototype = {
saveCanvas: vi.fn(),
elt: mockCanvas,
_curElement: {
elt: mockCanvas
}
},
canvas: {
id: 'myCanvasID'
},
_elements: []
};
86 changes: 47 additions & 39 deletions test/unit/accessibility/describe.js
Original file line number Diff line number Diff line change
@@ -1,142 +1,150 @@
import p5 from '../../../src/app.js';
import { mockP5, mockP5Prototype } from '../../js/mocks';
import describe from '../../../src/accessibility/describe';

suite('describe', function() {
let myp5;
let myID = 'myCanvasID';
const myID = 'myCanvasID';

beforeAll(function() {
new p5(function(p) {
p.setup = function() {
let cnv = p.createCanvas(100, 100);
cnv.id(myID);
myp5 = p;
};
});
});
describe(mockP5, mockP5Prototype);

afterAll(function() {
myp5.remove();
mockP5Prototype.LABEL = 'label';
mockP5Prototype.FALLBACK = 'fallback';
});

suite('p5.prototype.describe', function() {
test('should be a function', function() {
assert.ok(myp5.describe);
assert.typeOf(myp5.describe, 'function');
assert.ok(mockP5Prototype.describe);
assert.typeOf(mockP5Prototype.describe, 'function');
});

test('err when LABEL at param #0', function() {
assert.throws(
function() {
myp5.describe(myp5.LABEL);
mockP5Prototype.describe(mockP5Prototype.LABEL);
},
Error,
'description should not be LABEL or FALLBACK'
);
});

test('should create description as fallback', function() {
myp5.describe('a');
mockP5Prototype.describe('a');
let actual = document.getElementById(myID + '_fallbackDesc');
assert.deepEqual(actual.innerHTML, 'a.');
});

test('should not add extra period if string ends in "."', function() {
myp5.describe('A.');
mockP5Prototype.describe('A.');
let actual = document.getElementById(myID + '_fallbackDesc');
assert.deepEqual(actual.innerHTML, 'A.');
});

test('should not add period if string ends in "!" or "?', function() {
myp5.describe('A!');
mockP5Prototype.describe('A!');
let actual = document.getElementById(myID + '_fallbackDesc');
if (actual.innerHTML === 'A!') {
myp5.describe('A?');
mockP5Prototype.describe('A?');

actual = document.getElementById(myID + '_fallbackDesc');
assert.deepEqual(actual.innerHTML, 'A?');
}
});

test('should create description when called after describeElement()', function() {
myp5.describeElement('b', 'c');
myp5.describe('a');
mockP5Prototype.describeElement('b', 'c');
mockP5Prototype.describe('a');
let actual = document.getElementById(myID + '_fallbackDesc');
assert.deepEqual(actual.innerHTML, 'a.');
});

test('should create Label adjacent to canvas', function() {
myp5.describe('a', myp5.LABEL);
mockP5Prototype.describe('a', mockP5Prototype.LABEL);

let actual = document.getElementById(myID + '_labelDesc');
assert.deepEqual(actual.innerHTML, 'a.');
});

test('should create Label adjacent to canvas when label of element already exists', function() {
myp5.describeElement('ba', 'c', myp5.LABEL);
myp5.describe('a', myp5.LABEL);
mockP5Prototype.describeElement('ba', 'c', mockP5Prototype.LABEL);
mockP5Prototype.describe('a', mockP5Prototype.LABEL);
let actual = document.getElementById(myID + '_labelDesc');
assert.deepEqual(actual.innerHTML, 'a.');
});
});

suite('p5.prototype.describeElement', function() {
test('should be a function', function() {
assert.ok(myp5.describeElement);
assert.typeOf(myp5.describeElement, 'function');
assert.ok(mockP5Prototype.describeElement);
assert.typeOf(mockP5Prototype.describeElement, 'function');
});

test('err when LABEL at param #0', function() {
assert.throws(
function() {
myp5.describeElement(myp5.LABEL, 'b');
mockP5Prototype.describeElement(mockP5Prototype.LABEL, 'b');
},
Error,
'element name should not be LABEL or FALLBACK'
);
});

test('err when LABEL at param #1', function() {
assert.throws(
function() {
myp5.describeElement('a', myp5.LABEL);
mockP5Prototype.describeElement('a', mockP5Prototype.LABEL);
},
Error,
'description should not be LABEL or FALLBACK'
);
});

test('should create element description as fallback', function() {
myp5.describeElement('az', 'b');
mockP5Prototype.describeElement('az', 'b');
let actual = document.getElementById(myID + '_fte_az').innerHTML;
assert.deepEqual(actual, '<th scope="row">az:</th><td>b.</td>');
});

test('should not add extra ":" if element name ends in colon', function() {
myp5.describeElement('ab:', 'b.');
mockP5Prototype.describeElement('ab:', 'b.');
let actual = document.getElementById(myID + '_fte_ab').innerHTML;
assert.deepEqual(actual, '<th scope="row">ab:</th><td>b.</td>');
});

test('should replace ";", ",", "." for ":" in element name', function() {
let actual;
myp5.describeElement('ac;', 'b.');
mockP5Prototype.describeElement('ac;', 'b.');
if (
document.getElementById(myID + '_fte_ac').innerHTML ===
'<th scope="row">ac:</th><td>b.</td>'
) {
myp5.describeElement('ad,', 'b.');
mockP5Prototype.describeElement('ad,', 'b.');
if (
document.getElementById(myID + '_fte_ad').innerHTML ===
'<th scope="row">ad:</th><td>b.</td>'
) {
myp5.describeElement('ae.', 'b.');
mockP5Prototype.describeElement('ae.', 'b.');
actual = document.getElementById(myID + '_fte_ae').innerHTML;
assert.deepEqual(actual, '<th scope="row">ae:</th><td>b.</td>');
}
}
});

test('should create element description when called after describe()', function() {
myp5.describe('c');
myp5.describeElement('af', 'b');
mockP5Prototype.describe('c');
mockP5Prototype.describeElement('af', 'b');
let actual = document.getElementById(myID + '_fte_af').innerHTML;
assert.deepEqual(actual, '<th scope="row">af:</th><td>b.</td>');
});

test('should create element label adjacent to canvas', function() {
myp5.describeElement('ag', 'b', myp5.LABEL);
mockP5Prototype.describeElement('ag', 'b', mockP5Prototype.LABEL);
const actual = document.getElementById(myID + '_lte_ag').innerHTML;
assert.deepEqual(actual, '<th scope="row">ag:</th><td>b.</td>');
});

test('should create element label adjacent to canvas when called after describe()', function() {
myp5.describe('c', myp5.LABEL);
myp5.describeElement('ah:', 'b', myp5.LABEL);
mockP5Prototype.describe('c', mockP5Prototype.LABEL);
mockP5Prototype.describeElement('ah:', 'b', mockP5Prototype.LABEL);
const actual = document.getElementById(myID + '_lte_ah').innerHTML;
assert.deepEqual(actual, '<th scope="row">ah:</th><td>b.</td>');
});
Expand Down
Loading

0 comments on commit 7af092f

Please sign in to comment.