From bcc63cc08ce752e339c4c0b5855aded330f38a3e Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Mon, 2 Sep 2024 16:27:16 +0100 Subject: [PATCH 01/11] Added test for lrc --- test/BeaconLrc.test.js | 96 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 test/BeaconLrc.test.js diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js new file mode 100644 index 0000000..cfb4570 --- /dev/null +++ b/test/BeaconLrc.test.js @@ -0,0 +1,96 @@ +import assert from 'assert'; +import BeaconLrc from '../src/BeaconLrc.js'; + +describe('BeaconLrc', function() { + let beaconLrc; + let mockElement; + + beforeEach(function() { + // Mocking document.querySelectorAll + global.document = { + querySelectorAll: (selector) => { + if (selector === '[data-rocket-location-hash]') { + return [ + { getAttribute: () => 'hash1', dataset: { rocketLocationHash: 'hash1' } }, + { getAttribute: () => 'hash2', dataset: { rocketLocationHash: 'hash2' } }, + { getAttribute: () => 'hash3', dataset: { rocketLocationHash: 'hash3' } } + ]; + } + return []; + }, + documentElement: { scrollTop: 100 } // Ensure documentElement is part of the mock + }; + + // Mocking the methods of BeaconLrc + BeaconLrc.prototype._skipElement = function(element) { + return element.dataset.rocketLocationHash === 'hash3'; + }; + + BeaconLrc.prototype._getElementDepth = function(element) { + return 1; + }; + + BeaconLrc.prototype._getElementDistance = function(element) { + return 100; // Mocked distance updated to 100 + }; + + BeaconLrc.prototype._getLocationHash = function(element) { + return element.dataset.rocketLocationHash; + }; + + const config = { skipStrings: ['memex'] }; + const logger = { logMessage: () => {}, logColoredMessage: () => {} }; + beaconLrc = new BeaconLrc(config, logger); + + mockElement = { + getBoundingClientRect: () => ({ top: 200 }), + }; + + // Mocking window.pageYOffset + global.window = { pageYOffset: 100 }; + }); + + afterEach(function() { + delete global.window; + delete global.document; + }); + + it('should return valid elements with depth, distance, and hash', function() { + const elements = beaconLrc._getLazyRenderElements(); + assert(Array.isArray(elements)); + assert.strictEqual(elements.length, 2); + + assert.strictEqual(elements[0].hash, 'hash1'); + assert.strictEqual(elements[0].depth, 1); + assert.strictEqual(elements[0].distance, 100); + + assert.strictEqual(elements[1].hash, 'hash2'); + assert.strictEqual(elements[1].depth, 1); + assert.strictEqual(elements[1].distance, 100); + }); + + it('should skip elements based on config skipStrings', function() { + const elements = beaconLrc._getLazyRenderElements(); + const skippedElement = elements.find(el => el.hash === 'hash3'); + assert.strictEqual(skippedElement, undefined); + }); + + it('should return correct distance', () => { + BeaconLrc.prototype._getElementDistance = function(element) { + return 300; // Mocked distance updated to 300 for this test + }; + const distance = beaconLrc._getElementDistance(mockElement); + assert.strictEqual(distance, 300); + }); + + it('should return 0 if distance is negative', () => { + BeaconLrc.prototype._getElementDistance = function(element) { + const rect = element.getBoundingClientRect(); + const distance = rect.top + global.window.pageYOffset - global.document.documentElement.scrollTop; + return distance < 0 ? 0 : distance; + }; + mockElement.getBoundingClientRect = () => ({ top: -300 }); + const distance = beaconLrc._getElementDistance(mockElement); + assert.strictEqual(distance, 0); + }); +}); \ No newline at end of file From e6c6ecdf489f779c1356b3549f02bdce2bb110b8 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Mon, 2 Sep 2024 19:32:54 +0100 Subject: [PATCH 02/11] Best practices --- test/BeaconLrc.test.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index cfb4570..f12b594 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -26,11 +26,11 @@ describe('BeaconLrc', function() { return element.dataset.rocketLocationHash === 'hash3'; }; - BeaconLrc.prototype._getElementDepth = function(element) { + BeaconLrc.prototype._getElementDepth = function() { return 1; }; - BeaconLrc.prototype._getElementDistance = function(element) { + BeaconLrc.prototype._getElementDistance = function() { return 100; // Mocked distance updated to 100 }; @@ -39,7 +39,14 @@ describe('BeaconLrc', function() { }; const config = { skipStrings: ['memex'] }; - const logger = { logMessage: () => {}, logColoredMessage: () => {} }; + const logger = { + logMessage: (message) => { + console.log(`Log: ${message}`); + }, + logColoredMessage: (message, color) => { + console.log(`%c${message}`, `color: ${color}`); + } + }; beaconLrc = new BeaconLrc(config, logger); mockElement = { From a111d6bcfe70f6fef65fee85e64715b60fffd954 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Mon, 2 Sep 2024 19:36:13 +0100 Subject: [PATCH 03/11] Additional best practices --- test/BeaconLrc.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index f12b594..6ca8cde 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -83,7 +83,7 @@ describe('BeaconLrc', function() { }); it('should return correct distance', () => { - BeaconLrc.prototype._getElementDistance = function(element) { + BeaconLrc.prototype._getElementDistance = function() { return 300; // Mocked distance updated to 300 for this test }; const distance = beaconLrc._getElementDistance(mockElement); From 5455ec2000722370d33470129ad058083b9cbd87 Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 13:19:54 +0300 Subject: [PATCH 04/11] change the structure of test to handle more cases and use sinon for mocking --- test/BeaconLrc.test.js | 140 ++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 37 deletions(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index 6ca8cde..ead7fc2 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -1,43 +1,67 @@ import assert from 'assert'; import BeaconLrc from '../src/BeaconLrc.js'; +import sinon from "sinon"; describe('BeaconLrc', function() { let beaconLrc; let mockElement; + let mockElements; beforeEach(function() { + mockElements = [ + { + getBoundingClientRect: () => { + return { + top : 0, + }; + }, + getAttribute: () => 'hash1', + hasAttribute: () => true, + dataset: { rocketLocationHash: 'hash1' } + }, + { + getBoundingClientRect: () => { + return { + top : 0, + }; + }, + getAttribute: () => 'hash2', + hasAttribute: () => true, + dataset: { rocketLocationHash: 'hash2' } + }, + { + getBoundingClientRect: () => { + return { + top : 200, + }; + }, + getAttribute: () => 'hash3', + hasAttribute: () => true, + dataset: { rocketLocationHash: 'hash3' } + }, + { + getBoundingClientRect: () => { + return { + top : -300, + }; + }, + getAttribute: () => 'hash4', + hasAttribute: () => true, + dataset: { rocketLocationHash: 'hash4' } + }, + ]; + // Mocking document.querySelectorAll global.document = { querySelectorAll: (selector) => { if (selector === '[data-rocket-location-hash]') { - return [ - { getAttribute: () => 'hash1', dataset: { rocketLocationHash: 'hash1' } }, - { getAttribute: () => 'hash2', dataset: { rocketLocationHash: 'hash2' } }, - { getAttribute: () => 'hash3', dataset: { rocketLocationHash: 'hash3' } } - ]; + return mockElements; } return []; }, documentElement: { scrollTop: 100 } // Ensure documentElement is part of the mock }; - // Mocking the methods of BeaconLrc - BeaconLrc.prototype._skipElement = function(element) { - return element.dataset.rocketLocationHash === 'hash3'; - }; - - BeaconLrc.prototype._getElementDepth = function() { - return 1; - }; - - BeaconLrc.prototype._getElementDistance = function() { - return 100; // Mocked distance updated to 100 - }; - - BeaconLrc.prototype._getLocationHash = function(element) { - return element.dataset.rocketLocationHash; - }; - const config = { skipStrings: ['memex'] }; const logger = { logMessage: (message) => { @@ -49,10 +73,6 @@ describe('BeaconLrc', function() { }; beaconLrc = new BeaconLrc(config, logger); - mockElement = { - getBoundingClientRect: () => ({ top: 200 }), - }; - // Mocking window.pageYOffset global.window = { pageYOffset: 100 }; }); @@ -62,7 +82,25 @@ describe('BeaconLrc', function() { delete global.document; }); + it('should return empty elements', function() { + global.document = { + querySelectorAll: (selector) => { + return []; + }, + }; + const elements = beaconLrc._getLazyRenderElements(); + assert(Array.isArray(elements)); + assert.strictEqual(elements.length, 0); + }); + it('should return valid elements with depth, distance, and hash', function() { + const _getElementDepthStub = sinon.stub(beaconLrc, '_getElementDepth'); + _getElementDepthStub.returns(1); + + const _skipElementStub = sinon.stub(beaconLrc, '_skipElement'); + _skipElementStub.withArgs(mockElements[2]).returns(true); + _skipElementStub.withArgs(mockElements[3]).returns(true); + const elements = beaconLrc._getLazyRenderElements(); assert(Array.isArray(elements)); assert.strictEqual(elements.length, 2); @@ -74,30 +112,58 @@ describe('BeaconLrc', function() { assert.strictEqual(elements[1].hash, 'hash2'); assert.strictEqual(elements[1].depth, 1); assert.strictEqual(elements[1].distance, 100); + + _getElementDepthStub.restore(); + _skipElementStub.restore(); }); it('should skip elements based on config skipStrings', function() { + const _getElementDepthStub = sinon.stub(beaconLrc, '_getElementDepth'); + _getElementDepthStub.returns(1); + + const _skipElementStub = sinon.stub(beaconLrc, '_skipElement'); + _skipElementStub.withArgs(mockElements[2]).returns(true); + _skipElementStub.withArgs(mockElements[3]).returns(true); + const elements = beaconLrc._getLazyRenderElements(); const skippedElement = elements.find(el => el.hash === 'hash3'); assert.strictEqual(skippedElement, undefined); + + _getElementDepthStub.restore(); + _skipElementStub.restore(); }); it('should return correct distance', () => { - BeaconLrc.prototype._getElementDistance = function() { - return 300; // Mocked distance updated to 300 for this test - }; - const distance = beaconLrc._getElementDistance(mockElement); + const distance = beaconLrc._getElementDistance(mockElements[2]); assert.strictEqual(distance, 300); }); it('should return 0 if distance is negative', () => { - BeaconLrc.prototype._getElementDistance = function(element) { - const rect = element.getBoundingClientRect(); - const distance = rect.top + global.window.pageYOffset - global.document.documentElement.scrollTop; - return distance < 0 ? 0 : distance; - }; - mockElement.getBoundingClientRect = () => ({ top: -300 }); - const distance = beaconLrc._getElementDistance(mockElement); + const distance = beaconLrc._getElementDistance(mockElements[3]); assert.strictEqual(distance, 0); }); + + it('should return correct depth', () => { + const elementWithNoParent = { + parentElement: null, + }; + assert.strictEqual(beaconLrc._getElementDepth(elementWithNoParent), 0); + + const elementWithoneParent = { + parentElement: { + tagName: 'DIV', + }, + }; + assert.strictEqual(beaconLrc._getElementDepth(elementWithoneParent), 1); + + const elementWithTwoLevels = { + parentElement: { + tagName: 'DIV', + parentElement: { + tagName: 'DIV', + }, + }, + }; + assert.strictEqual(beaconLrc._getElementDepth(elementWithTwoLevels), 2); + }); }); \ No newline at end of file From 83ff74266c924f104d3b5dc7648b5433a2c354ba Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 14:33:14 +0300 Subject: [PATCH 05/11] test --- test/BeaconLrc.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index ead7fc2..eb1f11b 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -4,7 +4,6 @@ import sinon from "sinon"; describe('BeaconLrc', function() { let beaconLrc; - let mockElement; let mockElements; beforeEach(function() { @@ -107,6 +106,7 @@ describe('BeaconLrc', function() { assert.strictEqual(elements[0].hash, 'hash1'); assert.strictEqual(elements[0].depth, 1); + console.log( elements ); assert.strictEqual(elements[0].distance, 100); assert.strictEqual(elements[1].hash, 'hash2'); From 82e19b5341f4155a2b9aed87af309b6ec49c971b Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 15:22:49 +0300 Subject: [PATCH 06/11] test 2 --- src/BeaconLrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BeaconLrc.js b/src/BeaconLrc.js index a4f8bcd..e496bfc 100644 --- a/src/BeaconLrc.js +++ b/src/BeaconLrc.js @@ -52,6 +52,7 @@ class BeaconLrc { _getElementDistance(element) { const rect = element.getBoundingClientRect(); const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + console.log( rect, scrollTop ); return Math.max(0, rect.top + scrollTop); } From 8bfde1928e79b95692bc4c80c3ff840b8ead5ae2 Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 15:32:24 +0300 Subject: [PATCH 07/11] fix tests attempt 1 --- src/BeaconLrc.js | 1 - test/BeaconLrc.test.js | 15 ++++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/BeaconLrc.js b/src/BeaconLrc.js index 9451dad..6e7b97b 100644 --- a/src/BeaconLrc.js +++ b/src/BeaconLrc.js @@ -51,7 +51,6 @@ class BeaconLrc { _getElementDistance(element) { const rect = element.getBoundingClientRect(); const scrollTop = window.pageYOffset || document.documentElement.scrollTop; - console.log( rect, scrollTop ); return Math.max(0, rect.top + scrollTop - BeaconUtils.getScreenHeight()); } diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index eb1f11b..c212f11 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -21,7 +21,7 @@ describe('BeaconLrc', function() { { getBoundingClientRect: () => { return { - top : 0, + top : 800, }; }, getAttribute: () => 'hash2', @@ -31,7 +31,7 @@ describe('BeaconLrc', function() { { getBoundingClientRect: () => { return { - top : 200, + top : 1000, }; }, getAttribute: () => 'hash3', @@ -73,7 +73,7 @@ describe('BeaconLrc', function() { beaconLrc = new BeaconLrc(config, logger); // Mocking window.pageYOffset - global.window = { pageYOffset: 100 }; + global.window = { pageYOffset: 100, innerHeight: 500 }; }); afterEach(function() { @@ -104,14 +104,15 @@ describe('BeaconLrc', function() { assert(Array.isArray(elements)); assert.strictEqual(elements.length, 2); + console.log(elements[0].hash); assert.strictEqual(elements[0].hash, 'hash1'); assert.strictEqual(elements[0].depth, 1); - console.log( elements ); - assert.strictEqual(elements[0].distance, 100); + assert.strictEqual(elements[0].distance, 0); + console.log(elements[1].hash); assert.strictEqual(elements[1].hash, 'hash2'); assert.strictEqual(elements[1].depth, 1); - assert.strictEqual(elements[1].distance, 100); + assert.strictEqual(elements[1].distance, 400); _getElementDepthStub.restore(); _skipElementStub.restore(); @@ -135,7 +136,7 @@ describe('BeaconLrc', function() { it('should return correct distance', () => { const distance = beaconLrc._getElementDistance(mockElements[2]); - assert.strictEqual(distance, 300); + assert.strictEqual(distance, 600); }); it('should return 0 if distance is negative', () => { From 3e7be555e1758a6df3b71b4ea737066cb71aadda Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 15:57:07 +0300 Subject: [PATCH 08/11] add more tests --- src/BeaconLrc.js | 2 +- test/BeaconLrc.test.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/BeaconLrc.js b/src/BeaconLrc.js index 6e7b97b..3f96e91 100644 --- a/src/BeaconLrc.js +++ b/src/BeaconLrc.js @@ -57,7 +57,7 @@ class BeaconLrc { _skipElement(element) { const skipStrings = this.config.skipStrings || ['memex']; if (!element || !element.id) return false; - return skipStrings.some(str => element.id.toLowerCase().includes(str)); + return skipStrings.some(str => element.id.toLowerCase().includes(str.toLowerCase())); } _shouldSkipElement(element, exclusions) { diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index c212f11..bcc9de1 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -167,4 +167,24 @@ describe('BeaconLrc', function() { }; assert.strictEqual(beaconLrc._getElementDepth(elementWithTwoLevels), 2); }); + + it('_skipElement', () => { + // Empty config + const configStub = sinon.stub(beaconLrc, 'config'); + configStub.value({}); + assert.strictEqual(beaconLrc._skipElement({id: 'anyid'}), false); + + // Empty element + assert.strictEqual(beaconLrc._skipElement(), false); + + // Custom config + configStub.value({skipStrings: ['anyid', 'customid']}); + assert.strictEqual(beaconLrc._skipElement({id: 'anyid'}), true); + + // Case-insensitive + configStub.value({skipStrings: ['aNyid', 'customid']}); + assert.strictEqual(beaconLrc._skipElement({id: 'AnyId'}), true); + + configStub.restore(); + }); }); \ No newline at end of file From 2bc5ca48e80cd4da11c196da109e43dc98b27ab4 Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 17:17:10 +0300 Subject: [PATCH 09/11] add tests for run method --- test/BeaconLrc.test.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index bcc9de1..0db5a17 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -104,12 +104,10 @@ describe('BeaconLrc', function() { assert(Array.isArray(elements)); assert.strictEqual(elements.length, 2); - console.log(elements[0].hash); assert.strictEqual(elements[0].hash, 'hash1'); assert.strictEqual(elements[0].depth, 1); assert.strictEqual(elements[0].distance, 0); - console.log(elements[1].hash); assert.strictEqual(elements[1].hash, 'hash2'); assert.strictEqual(elements[1].depth, 1); assert.strictEqual(elements[1].distance, 400); @@ -187,4 +185,38 @@ describe('BeaconLrc', function() { configStub.restore(); }); + + it('run with empty elements', async () => { + const beaconMock = sinon.mock(beaconLrc); + + // Empty elements + beaconMock.expects("_getLazyRenderElements").returns(''); + beaconMock.expects("_processElements").withArgs('').never(); + await beaconLrc.run(); + + beaconMock.restore(); + }); + + it('run with thrown errors', async () => { + const beaconMock = sinon.mock(beaconLrc); + + // Throws error + beaconMock.expects("_getLazyRenderElements").throws('test error'); + beaconMock.expects("_processElements").never(); + await beaconLrc.run(); + beaconMock.verify(); + + beaconMock.restore(); + }); + + it('run with valid elements', async () => { + const beaconMock = sinon.mock(beaconLrc); + + // Valid elements + beaconMock.expects("_getLazyRenderElements").returns(['test']); + beaconMock.expects("_processElements").withArgs(['test']).once(); + await beaconLrc.run(); + + beaconMock.restore(); + }); }); \ No newline at end of file From e050e9e1cc5046457880a36d5b506bb64b8b6306 Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Mon, 9 Sep 2024 19:38:16 +0300 Subject: [PATCH 10/11] add more tests --- src/BeaconLrc.js | 2 +- test/BeaconLrc.test.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/BeaconLrc.js b/src/BeaconLrc.js index 3f96e91..52fd10d 100644 --- a/src/BeaconLrc.js +++ b/src/BeaconLrc.js @@ -102,7 +102,7 @@ class BeaconLrc { } _getXPath(element) { - if (element.id !== "") { + if (element && element.id !== "") { return `//*[@id="${element.id}"]`; } diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index 0db5a17..e3f45f4 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -219,4 +219,17 @@ describe('BeaconLrc', function() { beaconMock.restore(); }); + + it('_getXPath', () => { + const _getElementXPathStub = sinon.stub(beaconLrc, '_getElementXPath'); + _getElementXPathStub.returns('test'); + + // No element + assert.strictEqual(beaconLrc._getXPath(), 'test'); + + // No ID + assert.strictEqual(beaconLrc._getXPath({id: 'testID'}), '//*[@id="testID"]'); + + _getElementXPathStub.restore(); + }); }); \ No newline at end of file From 8f50b8feb4daa2df30a5631d772a5011fa65d756 Mon Sep 17 00:00:00 2001 From: WordPressFan Date: Tue, 10 Sep 2024 00:26:10 +0300 Subject: [PATCH 11/11] remove not used argument --- test/BeaconLrc.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/BeaconLrc.test.js b/test/BeaconLrc.test.js index e3f45f4..d0724be 100644 --- a/test/BeaconLrc.test.js +++ b/test/BeaconLrc.test.js @@ -83,7 +83,7 @@ describe('BeaconLrc', function() { it('should return empty elements', function() { global.document = { - querySelectorAll: (selector) => { + querySelectorAll: () => { return []; }, };