From 48a5bf1fb05da5ee6222c7b0a98e14a029eee90b Mon Sep 17 00:00:00 2001 From: Guilherme Correia Date: Tue, 8 Aug 2023 22:01:45 -0300 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=93=8C=20Fix=20dependencies=20above?= =?UTF-8?q?=20deprecations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 3317b85..75a446a 100644 --- a/package.json +++ b/package.json @@ -16,29 +16,27 @@ }, "dependencies": { "@swc/core": "1.3.35", - "babel-loader": "9.1.2", "body-parser": "1.20.1", "commander": "10.0.0", - "copy-webpack-plugin": "^11.0.0", + "copy-webpack-plugin": "11.0.0", "css-loader": "6.7.3", - "css-minimizer-webpack-plugin": "^4.2.2", + "css-minimizer-webpack-plugin": "5.0.1", "dotenv": "16.0.3", "eslint-plugin-nullstack": "0.0.26", "express": "4.18.2", "fs-extra": "11.1.0", - "lightningcss": "^1.19.0", + "lightningcss": "1.21.5", "mini-css-extract-plugin": "2.7.2", "node-fetch": "2.6.7", - "nodemon-webpack-plugin": "^4.8.1", + "nodemon-webpack-plugin": "4.8.1", "sass": "1.58.0", "sass-loader": "13.2.0", - "style-loader": "^3.3.1", + "style-loader": "3.3.3", "swc-loader": "0.2.3", "swc-plugin-nullstack": "0.1.3", "terser-webpack-plugin": "5.3.6", - "webpack": "^5.0.0", - "webpack-dev-server": "4.11.1", - "webpack-hot-middleware": "^2.25.3" + "webpack": "5.88.1", + "webpack-hot-middleware": "2.25.4" }, "devDependencies": { "webpack-dev-middleware": "github:Mortaro/webpack-dev-middleware#fix-write-to-disk-cleanup" From 30f10d7c12b30049e485ffac019e0594a10d0411 Mon Sep 17 00:00:00 2001 From: Guilherme Correia Date: Mon, 14 Aug 2023 19:53:32 -0300 Subject: [PATCH 02/15] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Add=20type=20to?= =?UTF-8?q?=20inner=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/index.d.ts b/types/index.d.ts index b2243c4..380e297 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -100,6 +100,8 @@ export default class Nullstack { render?(context: NullstackClientContext): NullstackNode + [_property: `render${Capitalize}`]: Nullstack['render'] + prerendered: boolean /** From 7a74807da0699c8bc21fbf8e4de57876294bd9be Mon Sep 17 00:00:00 2001 From: hallexcosta Date: Fri, 18 Aug 2023 00:30:39 -0300 Subject: [PATCH 03/15] add utility function symbolHashSplit --- shared/symbolHashSplit.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 shared/symbolHashSplit.js diff --git a/shared/symbolHashSplit.js b/shared/symbolHashSplit.js new file mode 100644 index 0000000..c395e33 --- /dev/null +++ b/shared/symbolHashSplit.js @@ -0,0 +1,3 @@ +export default function symbolHashSplit(hash) { + return hash.split('---') +} \ No newline at end of file From 05ec145346b409b64ddfaaaf8ad1b4e665ae7e9e Mon Sep 17 00:00:00 2001 From: hallexcosta Date: Fri, 18 Aug 2023 00:31:17 -0300 Subject: [PATCH 04/15] change seperator hash to --- --- server/server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/server.js b/server/server.js index 45e7361..5434993 100644 --- a/server/server.js +++ b/server/server.js @@ -2,6 +2,7 @@ import bodyParser from 'body-parser' import express from 'express' import path from 'path' import deserialize from '../shared/deserialize' +import symbolHashSplit from '../shared/symbolHashSplit' import prefix from '../shared/prefix' import context, { getCurrentContext, generateCurrentContext } from './context' import emulatePrerender from './emulatePrerender' @@ -123,7 +124,7 @@ server.start = function () { const payload = request.method === 'GET' ? request.query.payload : request.body const args = deserialize(payload) const { hash, methodName } = request.params - const [invokerHash, boundHash] = hash.split('-') + const [invokerHash, boundHash] = symbolHashSplit(hash) const key = `${invokerHash}.${methodName}` await load(boundHash || invokerHash) const invokerKlass = registry[invokerHash] @@ -154,7 +155,7 @@ server.start = function () { const payload = request.method === 'GET' ? request.query.payload : request.body const args = deserialize(payload) const { version, hash, methodName } = request.params - const [invokerHash, boundHash] = hash.split('-') + const [invokerHash, boundHash] = symbolHashSplit(hash) let [filePath, klassName] = (invokerHash || boundHash).split("___") const file = path.resolve('..', filePath.replaceAll('__', '/')) console.info('\x1b[1;37m%s\x1b[0m', ` [${request.method}] ${request.path}`) From a4fe03be041485234c17ced679ac0f5e24182285 Mon Sep 17 00:00:00 2001 From: hallexcosta Date: Fri, 18 Aug 2023 00:31:44 -0300 Subject: [PATCH 05/15] use utility function symbolHashSplit --- client/invoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/invoke.js b/client/invoke.js index 83b6df1..0c11a7e 100644 --- a/client/invoke.js +++ b/client/invoke.js @@ -13,7 +13,7 @@ export default function invoke(name, hash) { } else { worker.queues[name] = [...worker.queues[name], params] } - let finalHash = hash === this.hash ? hash : `${hash}-${this.hash}` + let finalHash = hash === this.hash ? hash : `${hash}---${this.hash}` let url = `${worker.api}/${prefix}/${finalHash}/${name}.json` if (module.hot) { const version = client.klasses[hash].__hashes[name] From 707943407751391c165c52120da1fca3be7d2a0c Mon Sep 17 00:00:00 2001 From: hallexcosta Date: Fri, 18 Aug 2023 14:49:52 -0300 Subject: [PATCH 06/15] feat: add new func symbolHashJoin and rename shared file to symbolHash.js --- client/invoke.js | 3 ++- server/server.js | 2 +- shared/symbolHash.js | 7 +++++++ shared/symbolHashSplit.js | 3 --- 4 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 shared/symbolHash.js delete mode 100644 shared/symbolHashSplit.js diff --git a/client/invoke.js b/client/invoke.js index 0c11a7e..315a06a 100644 --- a/client/invoke.js +++ b/client/invoke.js @@ -1,5 +1,6 @@ import deserialize from '../shared/deserialize' import prefix from '../shared/prefix' +import { symbolHashJoin } from '../shared/symbolHash' import page from './page' import worker from './worker' import client from './client' @@ -13,7 +14,7 @@ export default function invoke(name, hash) { } else { worker.queues[name] = [...worker.queues[name], params] } - let finalHash = hash === this.hash ? hash : `${hash}---${this.hash}` + let finalHash = hash === this.hash ? hash : symbolHashJoin(hash, this.hash) let url = `${worker.api}/${prefix}/${finalHash}/${name}.json` if (module.hot) { const version = client.klasses[hash].__hashes[name] diff --git a/server/server.js b/server/server.js index 5434993..2672164 100644 --- a/server/server.js +++ b/server/server.js @@ -2,7 +2,7 @@ import bodyParser from 'body-parser' import express from 'express' import path from 'path' import deserialize from '../shared/deserialize' -import symbolHashSplit from '../shared/symbolHashSplit' +import { symbolHashSplit } from '../shared/symbolHash' import prefix from '../shared/prefix' import context, { getCurrentContext, generateCurrentContext } from './context' import emulatePrerender from './emulatePrerender' diff --git a/shared/symbolHash.js b/shared/symbolHash.js new file mode 100644 index 0000000..53d59ad --- /dev/null +++ b/shared/symbolHash.js @@ -0,0 +1,7 @@ +export function symbolHashSplit(hash) { + return hash.split('---') +} + +export function symbolHashJoin(hash, joinHash) { + return `${hash}---${joinHash}` +} \ No newline at end of file diff --git a/shared/symbolHashSplit.js b/shared/symbolHashSplit.js deleted file mode 100644 index c395e33..0000000 --- a/shared/symbolHashSplit.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function symbolHashSplit(hash) { - return hash.split('---') -} \ No newline at end of file From a9ec053c3867a224333e083973e63696d6cef1d1 Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Tue, 22 Aug 2023 19:26:29 -0300 Subject: [PATCH 07/15] :bookmark: version 0.20.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 75a446a..005279b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nullstack", - "version": "0.20.0", + "version": "0.20.1", "description": "Feature-Driven Full Stack JavaScript Components", "main": "./types/index.d.ts", "author": "Mortaro", From de4df434839bfa7394b15b14a33fd9c6dbb31fa5 Mon Sep 17 00:00:00 2001 From: Guilherme Correia Date: Thu, 24 Aug 2023 00:23:48 -0300 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=9A=91=20Move=20`webpack-dev-middle?= =?UTF-8?q?ware`=20to=20prod=20deps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 005279b..a26b043 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,7 @@ "swc-plugin-nullstack": "0.1.3", "terser-webpack-plugin": "5.3.6", "webpack": "5.88.1", - "webpack-hot-middleware": "2.25.4" - }, - "devDependencies": { + "webpack-hot-middleware": "2.25.4", "webpack-dev-middleware": "github:Mortaro/webpack-dev-middleware#fix-write-to-disk-cleanup" } } \ No newline at end of file From 1f48102fcc948e173e814be30e76d6342effc32b Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Thu, 24 Aug 2023 12:03:09 -0300 Subject: [PATCH 09/15] :bookmark: version 0.20.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a26b043..afd9f8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nullstack", - "version": "0.20.1", + "version": "0.20.2", "description": "Feature-Driven Full Stack JavaScript Components", "main": "./types/index.d.ts", "author": "Mortaro", From 4acab9d496d0c890256e5f1c2543a7c0f7642f2f Mon Sep 17 00:00:00 2001 From: Guilherme Correia Date: Sat, 26 Aug 2023 21:04:48 -0300 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=9A=91=E2=AC=86=EF=B8=8F=20Update?= =?UTF-8?q?=20webpack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index afd9f8b..9a1a209 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "swc-loader": "0.2.3", "swc-plugin-nullstack": "0.1.3", "terser-webpack-plugin": "5.3.6", - "webpack": "5.88.1", + "webpack": "5.88.2", "webpack-hot-middleware": "2.25.4", "webpack-dev-middleware": "github:Mortaro/webpack-dev-middleware#fix-write-to-disk-cleanup" } From 62d753c838720b44ebac1e9703abe2c72f75642c Mon Sep 17 00:00:00 2001 From: Guilherme Correia Date: Tue, 29 Aug 2023 06:32:52 -0300 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=93=8C=20Move=20`webpack-dev-middle?= =?UTF-8?q?ware`=20from=20git=20to=20latest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index afd9f8b..5fda410 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,6 @@ "terser-webpack-plugin": "5.3.6", "webpack": "5.88.1", "webpack-hot-middleware": "2.25.4", - "webpack-dev-middleware": "github:Mortaro/webpack-dev-middleware#fix-write-to-disk-cleanup" + "webpack-dev-middleware": "6.1.1" } } \ No newline at end of file From fb4c5bf18c353ef5e9ef5c6ca9373818d87ce9ed Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Tue, 29 Aug 2023 16:53:47 -0300 Subject: [PATCH 12/15] :bookmark: version 0.20.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5db3987..83712d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nullstack", - "version": "0.20.2", + "version": "0.20.3", "description": "Feature-Driven Full Stack JavaScript Components", "main": "./types/index.d.ts", "author": "Mortaro", From 73df30ccd507347b65b9e46a1dd39ee6cb7c728d Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Mon, 1 Sep 2025 15:31:50 -0300 Subject: [PATCH 13/15] :sparkles: svg support --- client/render.js | 9 ++++--- client/rerender.js | 14 ++++++----- shared/nodes.js | 2 +- tests/src/Application.njs | 2 ++ tests/src/SvgSupport.njs | 46 ++++++++++++++++++++++++++++++++++++ tests/src/SvgSupport.test.js | 22 +++++++++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 tests/src/SvgSupport.njs create mode 100644 tests/src/SvgSupport.test.js diff --git a/client/render.js b/client/render.js index 7fee343..e137652 100644 --- a/client/render.js +++ b/client/render.js @@ -5,7 +5,7 @@ import { anchorableElement } from './anchorableNode' import { generateCallback, generateSubject } from './events' import { ref } from './ref' -export default function render(node, options) { +export default function render(node, isSvg = false) { if (isFalse(node) || node.type === 'head') { node.element = document.createComment('') return node.element @@ -16,9 +16,8 @@ export default function render(node, options) { return node.element } - const svg = (options && options.svg) || node.type === 'svg' - - if (svg) { + isSvg = isSvg || node.type === 'svg' + if (isSvg) { node.element = document.createElementNS('http://www.w3.org/2000/svg', node.type) } else { node.element = document.createElement(node.type) @@ -58,7 +57,7 @@ export default function render(node, options) { if (!node.attributes.html) { for (let i = 0; i < node.children.length; i++) { - const child = render(node.children[i], { svg }) + const child = render(node.children[i], isSvg) node.element.appendChild(child) } diff --git a/client/rerender.js b/client/rerender.js index cd788f6..512f9d6 100644 --- a/client/rerender.js +++ b/client/rerender.js @@ -100,7 +100,7 @@ function updateHeadChildren(currentChildren, nextChildren) { } } -function _rerender(current, next) { +function _rerender(current, next, isParentSvg = false) { const selector = current.element next.element = current.element @@ -108,8 +108,10 @@ function _rerender(current, next) { return } + const isSvg = isParentSvg || next.type === 'svg' + if (current.type !== next.type) { - const nextSelector = render(next) + const nextSelector = render(next, isSvg) selector.replaceWith(nextSelector) return } @@ -132,22 +134,22 @@ function _rerender(current, next) { const limit = Math.max(current.children.length, next.children.length) if (next.children.length > current.children.length) { for (let i = 0; i < current.children.length; i++) { - _rerender(current.children[i], next.children[i]) + _rerender(current.children[i], next.children[i], isSvg) } for (let i = current.children.length; i < next.children.length; i++) { - const nextSelector = render(next.children[i]) + const nextSelector = render(next.children[i], isSvg) selector.appendChild(nextSelector) } } else if (current.children.length > next.children.length) { for (let i = 0; i < next.children.length; i++) { - _rerender(current.children[i], next.children[i]) + _rerender(current.children[i], next.children[i], isSvg) } for (let i = current.children.length - 1; i >= next.children.length; i--) { selector.childNodes[i].remove() } } else { for (let i = limit - 1; i > -1; i--) { - _rerender(current.children[i], next.children[i]) + _rerender(current.children[i], next.children[i], isSvg) } } } diff --git a/shared/nodes.js b/shared/nodes.js index f1d3363..4da2564 100644 --- a/shared/nodes.js +++ b/shared/nodes.js @@ -18,5 +18,5 @@ export function isFunction(node) { } export function isText(node) { - return node.type === 'text' + return node.type === 'text' && node.attributes === undefined } diff --git a/tests/src/Application.njs b/tests/src/Application.njs index 58691b9..5bd8201 100644 --- a/tests/src/Application.njs +++ b/tests/src/Application.njs @@ -63,6 +63,7 @@ import LazyComponentLoader from './LazyComponentLoader' import NestedFolder from './nested/NestedFolder' import ChildComponentWithoutServerFunctions from './ChildComponentWithoutServerFunctions' import ObjectEventScope from './ObjectEventScope' +import SvgSupport from './SvgSupport.njs' import './Application.css' class Application extends Nullstack { @@ -156,6 +157,7 @@ class Application extends Nullstack { + ) diff --git a/tests/src/SvgSupport.njs b/tests/src/SvgSupport.njs new file mode 100644 index 0000000..6dcc98e --- /dev/null +++ b/tests/src/SvgSupport.njs @@ -0,0 +1,46 @@ +import Nullstack from 'nullstack'; + +function Close({ size }) { + return ( + + + + + ) +} + +function Hamburger({ size }) { + return ( + + + + + + ) +} + +class SvgSupport extends Nullstack { + + open = false + visible = false + + render() { + return ( +
+ + I + love + my + cat! + + {this.open ? : } + + {this.visible && } + +
+ ) + } + +} + +export default SvgSupport; \ No newline at end of file diff --git a/tests/src/SvgSupport.test.js b/tests/src/SvgSupport.test.js new file mode 100644 index 0000000..0a966a6 --- /dev/null +++ b/tests/src/SvgSupport.test.js @@ -0,0 +1,22 @@ +describe('SvgSupport', () => { + beforeEach(async () => { + await page.goto('http://localhost:6969/svg-support') + await page.waitForSelector('[data-hydrated]') + }) + + test('svg can render text', async () => { + expect(true).toBeTruthy() + }) + + test('svg can add new paths while rerendering', async () => { + expect(true).toBeTruthy() + }) + + test('svg can render in short circuit statements', async () => { + expect(true).toBeTruthy() + }) + + test('svg can render in ternary statements', async () => { + expect(true).toBeTruthy() + }) +}) From 0b51beb8097a7610645d1882bc6d2c1a621a814e Mon Sep 17 00:00:00 2001 From: Aylon Muramatsu Date: Mon, 6 Oct 2025 17:19:40 -0300 Subject: [PATCH 14/15] =?UTF-8?q?feat:=20implementa=20testes=20e=20adicion?= =?UTF-8?q?a=20corre=C3=A7=C3=A3o=20para=20render=20do=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/render.js | 4 +- tests/src/SvgSupport.njs | 2 +- tests/src/SvgSupport.test.js | 96 ++++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/server/render.js b/server/render.js index e1b565d..06e416c 100644 --- a/server/render.js +++ b/server/render.js @@ -1,4 +1,4 @@ -import { isFalse } from '../shared/nodes' +import { isFalse, isText } from '../shared/nodes' import { sanitizeHtml } from '../shared/sanitizeString' import renderAttributes from './renderAttributes' @@ -25,7 +25,7 @@ function renderBody(node, scope, next) { if (isFalse(node)) { return '' } - if (node.type === 'text') { + if (isText(node)) { const text = node.text === '' ? ' ' : sanitizeHtml(node.text.toString()) return next && next.type === 'text' ? `${text}` : text } diff --git a/tests/src/SvgSupport.njs b/tests/src/SvgSupport.njs index 6dcc98e..9080bc9 100644 --- a/tests/src/SvgSupport.njs +++ b/tests/src/SvgSupport.njs @@ -26,7 +26,7 @@ class SvgSupport extends Nullstack { render() { return ( -
+
I love diff --git a/tests/src/SvgSupport.test.js b/tests/src/SvgSupport.test.js index 0a966a6..b651061 100644 --- a/tests/src/SvgSupport.test.js +++ b/tests/src/SvgSupport.test.js @@ -5,18 +5,106 @@ describe('SvgSupport', () => { }) test('svg can render text', async () => { - expect(true).toBeTruthy() + // Verifica se o SVG possui 4 elementos dentro dele + const svg = await page.$('svg'); + const texts = await svg.$$('text'); + expect(texts.length).toBe(4); }) test('svg can add new paths while rerendering', async () => { - expect(true).toBeTruthy() + // Verifica se o ícone Hamburger está presente inicialmente (3 paths) + const hamburgerPaths = await page.$$('svg[width="30"] path') + expect(hamburgerPaths.length).toBe(3) // Hamburger has 3 paths }) test('svg can render in short circuit statements', async () => { - expect(true).toBeTruthy() + // Verifica se o ícone de Hamburger está sendo exibido (3 paths) + const hamburgerPaths = await page.$$('svg[width="30"] path') + expect(hamburgerPaths.length).toBe(3) }) test('svg can render in ternary statements', async () => { - expect(true).toBeTruthy() + let bigHamburger = await page.$('svg[width="69"]') + expect(bigHamburger).toBeFalsy() + + // Clica no segundo botão (show) + const buttons = await page.$$('button') + await buttons[1].click() + + // Aguarda o Hamburger grande aparecer + await page.waitForSelector('svg[width="69"]') + + // Verifica se o Hamburger foi renderizado no ternário + bigHamburger = await page.$('svg[width="69"]') + expect(bigHamburger).toBeTruthy() + + }) + + test('icon toggle functionality works correctly', async () => { + // Primeiro verifica o estado inicial (deve ser Hamburger, 3 paths) + let iconPaths = await page.$$('svg[width="30"] path') + expect(iconPaths.length).toBe(3) // Hamburger tem 3 paths + + // Clica no primeiro botão (toggle) + const buttons = await page.$$('button') + await buttons[0].click() + + // Aguarda o ícone trocar (Close tem 2 paths) + await page.waitForFunction(() => { + const svg = document.querySelector('svg[width="30"]'); + return svg && svg.querySelectorAll('path').length === 2; + }); + + iconPaths = await page.$$('svg[width="30"] path') + expect(iconPaths.length).toBe(2) // Close tem 2 paths + + // Clica novamente para voltar ao Hamburger + await buttons[0].click() + + // Aguarda o ícone trocar de volta (Hamburger tem 3 paths) + await page.waitForFunction(() => { + const svg = document.querySelector('svg[width="30"]'); + return svg && svg.querySelectorAll('path').length === 3; + }); + + iconPaths = await page.$$('svg[width="30"] path') + expect(iconPaths.length).toBe(3) // Hamburger tem 3 paths + }) + + test('icon visibility toggle works correctly', async () => { + + // Verifica que o ícone grande não está visível inicialmente + let bigHamburger = await page.$('svg[width="69"]') + expect(bigHamburger).toBeFalsy() + + // Clica no segundo botão (show) + const buttons = await page.$$('button') + await buttons[1].click() + + // Aguarda o Hamburger grande aparecer + await page.waitForSelector('svg[width="69"]') + + // Verifica se o Hamburger grande apareceu + bigHamburger = await page.$('svg[width="69"]') + expect(bigHamburger).toBeTruthy() + + // Clica novamente no segundo botão (show) para esconder + await buttons[1].click() + + // Aguarda o Hamburger grande desaparecer do DOM + await page.waitForSelector('svg[width="69"]', { hidden: true }) + + // Verifica se o Hamburger grande desapareceu + bigHamburger = await page.$('svg[width="69"]') + expect(bigHamburger).toBeFalsy() + }) + + test('svg attributes are correctly applied', async () => { + // Verifica se os atributos SVG estão sendo aplicados corretamente + const svgElement = await page.$('svg[viewBox="0 0 240 80"]') + expect(svgElement).toBeTruthy() + + const xmlns = await page.$eval('svg[viewBox="0 0 240 80"]', el => el.getAttribute('xmlns')) + expect(xmlns).toBe('http://www.w3.org/2000/svg') }) }) From ec5e51be540a98bab311ab02eef5c9c0231ec017 Mon Sep 17 00:00:00 2001 From: Christian Mortaro Date: Thu, 9 Oct 2025 22:21:05 -0300 Subject: [PATCH 15/15] :bookmark: version 0.20.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83712d5..970fece 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nullstack", - "version": "0.20.3", + "version": "0.20.4", "description": "Feature-Driven Full Stack JavaScript Components", "main": "./types/index.d.ts", "author": "Mortaro",