QA Testing | Evidencia verificable

Pruebas funcionales, automatización, regresión y documentación orientadas a verificar el comportamiento del software, detectar defectos y aportar evidencia reproducible.

01. Casos de prueba

Biblioteca interactiva de escenarios de prueba documentados para verificar el comportamiento del portfolio.

02. Automatización con Selenium

Pruebas automatizadas de interfaz para verificar validaciones, flujos de acceso y comportamiento funcional del portfolio.

Automatización de pruebas UI

Utilizo Selenium WebDriver para interactuar con la interfaz como lo haría un usuario y Node.js Test Runner para verificar los resultados mediante aserciones automatizadas.

12/12 PASS Suite UI original · 12 escenarios
36/36 PASS Suite UI · Regresión multinavegador · 21/10/2026
3 navegadores Chrome · Firefox · Edge
12/12 PASS Suite FR-012 · Validación de nombre y apellido · 30/10/2026
33/33 PASS Suite telefónica · 11 escenarios × 3 navegadores
15/15 PASS Suite de email · 5 escenarios × 3 navegadores
129/129 PASS Buscador global · 43 escenarios × 3 navegadores

Escenarios automatizados

TC-019 Navegación entre páginas del portfolio

¿Qué verifica?

Comprueba la carga directa de las cinco páginas internas y la navegación a ellas mediante los enlaces visibles del portfolio, verificando la URL y el contenido principal.

Código Selenium

const paginas = [
                        'cv.html',
                        'frontend.html',
                        'backend.html',
                        'qa.html',
                        'quality-management.html'
                    ];

                    // Prueba 1: carga directa de cada página.
                    for (const pagina of paginas) {
                        await driver.get(`${BASE_URL}/${pagina}`);
                        await driver.wait(until.elementLocated(By.css('body')), 10000);
                        const url = await driver.getCurrentUrl();
                        assert.ok(url.endsWith(`/${pagina}`));
                        const contenido = await driver.findElement(By.css('main'));
                        assert.equal(await contenido.isDisplayed(), true);
                    }

                    // Prueba 2: navegación desde enlaces del portfolio.
                    for (const pagina of paginas) {
                        await driver.get(`${BASE_URL}/index.html`);
                        await driver.executeScript(
                            "sessionStorage.removeItem('portfolioSession');"
                        );
                        await driver.navigate().refresh();
                        // Se completa el formulario de acceso con datos válidos.
                        // Se espera hasta que #portfolio esté visible.
                        const enlace = await driver.wait(
                            until.elementLocated(By.css(`a[href="${pagina}"]`)),
                            10000
                        );
                        assert.equal(await enlace.isDisplayed(), true);
                        await enlace.click();
                        await driver.wait(until.urlContains(`/${pagina}`), 10000);
                        assert.ok((await driver.getCurrentUrl()).endsWith(`/${pagina}`));
                    }

Extractos de las dos pruebas reales. La segunda también completa el formulario de acceso y espera que el portfolio sea visible antes de hacer clic. Archivo: portfolio-navigation.test.js.

TC-020 Retorno al perfil y a las secciones del Home

¿Qué verifica?

Verifica que el logo de cada página interna regrese a index.html y que los botones de retorno conduzcan a #about desde CV o a #qa desde las otras cuatro páginas, con la sección de destino visible.

Código Selenium

// Prueba 1: retorno mediante el logo.
                    for (const pagina of paginas) {
                        await driver.get(`${BASE_URL}/${pagina}`);
                        const enlace = await driver.wait(
                            until.elementLocated(By.css('a.logo[href="index.html"]')),
                            10000
                        );
                        assert.equal(await enlace.isDisplayed(), true);
                        await enlace.click();
                        await driver.wait(until.urlContains('/index.html'), 10000);
                        assert.ok((await driver.getCurrentUrl()).endsWith('/index.html'));
                    }

                    // Prueba 2: retorno mediante botones a secciones del Home.
                    const retornos = [
                        { pagina: 'cv.html', seccion: 'about' },
                        { pagina: 'frontend.html', seccion: 'qa' },
                        { pagina: 'backend.html', seccion: 'qa' },
                        { pagina: 'qa.html', seccion: 'qa' },
                        { pagina: 'quality-management.html', seccion: 'qa' }
                    ];

                    // Antes del recorrido se inicia una sesión válida.
                    for (const { pagina, seccion } of retornos) {
                        await driver.get(`${BASE_URL}/${pagina}`);
                        const boton = await driver.wait(
                            until.elementLocated(
                                By.css(`a.cv-back-button[href="index.html#${seccion}"]`)
                            ),
                            10000
                        );
                        assert.equal(await boton.isDisplayed(), true);
                        await boton.click();
                        await driver.wait(
                            until.urlIs(`${BASE_URL}/index.html#${seccion}`),
                            10000
                        );
                        assert.equal(
                            await driver.getCurrentUrl(),
                            `${BASE_URL}/index.html#${seccion}`
                        );
                        const destino = await driver.wait(
                            until.elementLocated(By.id(seccion)),
                            10000
                        );
                        await driver.wait(until.elementIsVisible(destino), 10000);
                        assert.equal(await destino.isDisplayed(), true);
                    }

Extractos de las dos pruebas reales. La segunda inicia una sesión válida antes de recorrer las cinco páginas y comprueba la visibilidad de cada sección de destino. Archivo: portfolio-navigation.test.js.

UI-001 Carga de la página y formulario

¿Qué verifica?

Comprueba que la página se abra, que el título sea correcto y que el formulario de acceso esté visible.

Código Selenium

const title = await driver.getTitle();

                                                assert.equal(
                                                    title,
                                                    'Miguel Flor | QA Tester & AI Consultant'
                                                );

                                                const accessForm = await driver.findElement(
                                                    By.id('accessForm')
                                                );

                                                assert.equal(await accessForm.isDisplayed(), true);

                                                const firstName = await driver.findElement(
                                                    By.id('firstName')
                                                );

                                                assert.equal(await firstName.isDisplayed(), true);
UI-002 Formulario vacío

¿Qué verifica?

Comprueba que los campos obligatorios muestren sus errores y que el portfolio permanezca oculto.

Código Selenium

await driver.findElement(
                                                    By.id('accessButton')
                                                ).click();

                                                const expectedErrors = {
                                                    firstNameError: 'El nombre es obligatorio.',
                                                    lastNameError: 'El apellido es obligatorio.',
                                                    emailError: 'El email es obligatorio.',
                                                    phoneError: 'El teléfono es obligatorio.',
                                                    consentError: 'Debés aceptar el registro de tus datos.'
                                                };

                                                for (const [errorId, expectedMessage] of Object.entries(expectedErrors)) {
                                                    const errorElement = await driver.findElement(By.id(errorId));

                                                    assert.equal(
                                                        await errorElement.getText(),
                                                        expectedMessage,
                                                        `Mensaje incorrecto en ${errorId}`
                                                    );
                                                }

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(await portfolio.isDisplayed(), false);
UI-003 Correo electrónico inválido

¿Qué verifica?

Valida que un correo con formato incorrecto impida el acceso al portfolio.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('Miguel');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('Flor');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('correo-invalido');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('1123456789');

                                                await driver.findElement(By.id('consent')).click();

                                                await driver.findElement(By.id('accessButton')).click();

                                                const emailError = await driver.findElement(
                                                    By.id('emailError')
                                                );

                                                assert.equal(
                                                    await emailError.getText(),
                                                    'Ingresá un email válido.',
                                                    'Debe mostrarse el mensaje de email inválido'
                                                );

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(
                                                    await portfolio.isDisplayed(),
                                                    false,
                                                    'El portfolio debe permanecer oculto'
                                                );
UI-004 Nombre demasiado corto

¿Qué verifica?

Comprueba que un nombre que no cumple la longitud mínima sea rechazado.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('M');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('Flor');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('miguel@example.com');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('1123456789');

                                                await driver.findElement(By.id('consent')).click();

                                                await driver.findElement(By.id('accessButton')).click();

                                                const firstNameError = await driver.findElement(
                                                    By.id('firstNameError')
                                                );

                                                assert.equal(
                                                    await firstNameError.getText(),
                                                    'Ingresá un nombre válido.',
                                                    'Debe mostrarse el mensaje de nombre inválido'
                                                );

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(
                                                    await portfolio.isDisplayed(),
                                                    false,
                                                    'El portfolio debe permanecer oculto'
                                                );
UI-005 Apellido demasiado corto

¿Qué verifica?

Verifica que un apellido inválido impida el acceso.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('Miguel');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('F');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('miguel@example.com');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('1123456789');

                                                await driver.findElement(By.id('consent')).click();

                                                await driver.findElement(By.id('accessButton')).click();

                                                const lastNameError = await driver.findElement(
                                                    By.id('lastNameError')
                                                );

                                                assert.equal(
                                                    await lastNameError.getText(),
                                                    'Ingresá un apellido válido.',
                                                    'Debe mostrarse el mensaje de apellido inválido'
                                                );

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(
                                                    await portfolio.isDisplayed(),
                                                    false,
                                                    'El portfolio debe permanecer oculto'
                                                );
BUG-001 Teléfono con caracteres alfabéticos

¿Qué verifica?

Verifica que el formulario rechace un teléfono que contiene letras, muestre el mensaje de validación correspondiente e impida el acceso al portfolio. Dato de prueba: 12345abc. Requisito: FR-008.

Código Selenium

const caso = {
                        id: 'BUG-001',
                        descripcion: 'caracteres alfabéticos',
                        valor: '12345abc',
                        valido: false
                    };

                    await driver.findElement(By.id('phone'))
                        .sendKeys(caso.valor);

                    await driver.findElement(By.id('consent')).click();

                    await driver.findElement(By.id('accessButton')).click();

                    const phoneError = await driver.findElement(
                        By.id('phoneError')
                    );

                    const portfolio = await driver.findElement(
                        By.id('portfolio')
                    );

                    assert.equal(
                        await phoneError.getText(),
                        'Ingresá un teléfono válido.',
                        `Debe rechazarse ${caso.valor}`
                    );

                    assert.equal(
                        await portfolio.isDisplayed(),
                        false,
                        `El portfolio debe permanecer oculto para ${caso.valor}`
                    );

Archivo: phone-validation-boundaries.test.js. Escenario BUG-001: 3/3 PASS en Chrome, Firefox y Edge. Esta prueba forma parte de la suite telefónica de 33/33 PASS.

BUG-002 Nombre con caracteres numéricos

¿Qué verifica?

Verifica que el formulario rechace un nombre que contiene números, muestre el mensaje de validación correspondiente e impida el acceso al portfolio. Dato de prueba: sdfh567. Requisito: FR-012.

Código Selenium

await driver.findElement(By.id('firstName'))
                        .sendKeys('sdfh567');

                    await driver.findElement(By.id('lastName'))
                        .sendKeys('Flor');

                    await driver.findElement(By.id('email'))
                        .sendKeys('miguel@example.com');

                    await driver.findElement(By.id('phone'))
                        .sendKeys('1123456789');

                    await driver.findElement(By.id('consent')).click();

                    await driver.findElement(By.id('accessButton')).click();

                    const firstNameError = await driver.findElement(
                        By.id('firstNameError')
                    );

                    assert.equal(
                        await firstNameError.getText(),
                        'Ingresá un nombre válido.'
                    );

                    const portfolio = await driver.findElement(
                        By.id('portfolio')
                    );

                    assert.equal(
                        await portfolio.isDisplayed(),
                        false
                    );
BUG-003 Apellido con caracteres numéricos

¿Qué verifica?

Verifica que el formulario rechace un apellido que contiene números, muestre el mensaje de validación correspondiente e impida el acceso al portfolio. Dato de prueba: Flor567. Requisito: FR-012.

Código Selenium

await driver.findElement(By.id('firstName'))
                        .sendKeys('Miguel');

                    await driver.findElement(By.id('lastName'))
                        .sendKeys('Flor567');

                    await driver.findElement(By.id('email'))
                        .sendKeys('miguel@example.com');

                    await driver.findElement(By.id('phone'))
                        .sendKeys('1123456789');

                    await driver.findElement(By.id('consent')).click();

                    await driver.findElement(By.id('accessButton')).click();

                    const lastNameError = await driver.findElement(
                        By.id('lastNameError')
                    );

                    assert.equal(
                        await lastNameError.getText(),
                        'Ingresá un apellido válido.'
                    );

                    const portfolio = await driver.findElement(
                        By.id('portfolio')
                    );

                    assert.equal(
                        await portfolio.isDisplayed(),
                        false
                    );
BUG-005 Validación de longitud máxima del teléfono

¿Qué verifica?

Verifica que un teléfono de 16 dígitos, superior al máximo permitido de 15, muestre el mensaje de validación correspondiente e impida el acceso al portfolio. Requisito: FR-008. Caso relacionado: TC-018.

Código Selenium

const caso = {
                        id: 'BUG-005',
                        descripcion: '16 dígitos',
                        valor: '1234567890123456',
                        valido: false
                    };

                    await driver.findElement(By.id('phone'))
                        .sendKeys(caso.valor);

                    await driver.findElement(By.id('consent')).click();

                    await driver.findElement(By.id('accessButton')).click();

                    const phoneError = await driver.findElement(
                        By.id('phoneError')
                    );

                    const portfolio = await driver.findElement(
                        By.id('portfolio')
                    );

                    assert.equal(
                        await phoneError.getText(),
                        'Ingresá un teléfono válido.',
                        `Debe rechazarse ${caso.valor}`
                    );

                    assert.equal(
                        await portfolio.isDisplayed(),
                        false,
                        `El portfolio debe permanecer oculto para ${caso.valor}`
                    );

Archivo: phone-validation-boundaries.test.js. Escenario BUG-005: 3/3 PASS en Chrome, Firefox y Edge. Suite telefónica completa: 33/33 PASS.

Cobertura de la suite telefónica

La suite incluye 11 escenarios de validación telefónica, ejecutados en Chrome, Firefox y Edge. Cada escenario obtuvo 3/3 PASS.

Caso Dato de prueba Resultado esperado
PHONE-0011234567Aceptado
PHONE-00212345678Aceptado
PHONE-003123456789012345Aceptado
BUG-0051234567890123456Rechazado
BUG-00112345abcRechazado
PHONE-00411 2345 6789Aceptado
PHONE-00511-2345-6789Aceptado
PHONE-006(11) 2345-6789Aceptado
PHONE-007+54 11 2345-6789Aceptado
PHONE-00812345@6789Rechazado
PHONE-009+-()Rechazado
UI-006 Teléfono demasiado corto

¿Qué verifica?

Comprueba que un teléfono de menos de siete dígitos sea rechazado.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('Miguel');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('Flor');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('miguel@example.com');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('123456');

                                                await driver.findElement(By.id('consent')).click();

                                                await driver.findElement(By.id('accessButton')).click();

                                                const phoneError = await driver.findElement(
                                                    By.id('phoneError')
                                                );

                                                assert.equal(
                                                    await phoneError.getText(),
                                                    'Ingresá un teléfono válido.',
                                                    'Debe mostrarse el mensaje de teléfono inválido'
                                                );

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(
                                                    await portfolio.isDisplayed(),
                                                    false,
                                                    'El portfolio debe permanecer oculto'
                                                );
UI-007 Consentimiento obligatorio

¿Qué verifica?

Confirma que el usuario no pueda acceder sin aceptar el registro de sus datos.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('Miguel');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('Flor');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('miguel@example.com');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('1123456789');

                                                const consent = await driver.findElement(By.id('consent'));

                                                assert.equal(
                                                    await consent.isSelected(),
                                                    false,
                                                    'El consentimiento debe estar desmarcado inicialmente'
                                                );

                                                await driver.findElement(By.id('accessButton')).click();

                                                const consentError = await driver.findElement(
                                                    By.id('consentError')
                                                );

                                                assert.equal(
                                                    await consentError.getText(),
                                                    'Debés aceptar el registro de tus datos.',
                                                    'Debe mostrarse el mensaje de consentimiento obligatorio'
                                                );

                                                const portfolio = await driver.findElement(By.id('portfolio'));

                                                assert.equal(
                                                    await portfolio.isDisplayed(),
                                                    false,
                                                    'El portfolio debe permanecer oculto'
                                                );
UI-008 Registro válido y acceso al portfolio

¿Qué verifica?

Comprueba que el registro válido permita ingresar y que el saludo muestre el nombre en mayúsculas.

Código Selenium

await driver.findElement(By.id('firstName'))
                                                    .sendKeys('Miguel');

                                                await driver.findElement(By.id('lastName'))
                                                    .sendKeys('Flor');

                                                await driver.findElement(By.id('email'))
                                                    .sendKeys('selenium.test@example.com');

                                                await driver.findElement(By.id('phone'))
                                                    .sendKeys('1123456789');

                                                await driver.findElement(By.id('consent')).click();
                                                await driver.findElement(By.id('accessButton')).click();

                                                const portfolio = await driver.wait(
                                                    until.elementIsVisible(
                                                        await driver.findElement(By.id('portfolio'))
                                                    ),
                                                    10000,
                                                    'El portfolio debería mostrarse después del registro válido.'
                                                );

                                                assert.equal(await portfolio.isDisplayed(), true);

                                                assert.equal(
                                                    await driver.findElement(By.id('accessPage')).isDisplayed(),
                                                    false,
                                                    'El formulario de acceso debería quedar oculto.'
                                                );

                                                const welcomeMessage = await driver.findElement(
                                                    By.id('welcomeMessage')
                                                );

                                                assert.equal(
                                                    await welcomeMessage.getText(),
                                                    'Te doy la bienvenida, MIGUEL',
                                                    'El saludo debe mostrar únicamente el nombre en mayúsculas.'
                                                );
UI-009 Cambio de idioma

¿Qué verifica?

Comprueba que el encabezado de acceso cambie entre español, inglés y portugués.

Código Selenium

const languageSelect = await driver.findElement(
                                                    By.id('languageSelect')
                                                );

                                                const accessWelcome = await driver.findElement(
                                                    By.css('[data-i18n="accessWelcome"]')
                                                );

                                                const languages = [
                                                    { code: 'es', expected: 'Te doy la bienvenida' },
                                                    { code: 'en', expected: 'Welcome' },
                                                    { code: 'pt', expected: 'Dou-lhe as boas-vindas' }
                                                ];

                                                for (const language of languages) {
                                                    await new Select(languageSelect).selectByValue(language.code);

                                                    assert.equal(
                                                        await accessWelcome.getText(),
                                                        language.expected,
                                                        `El encabezado debería mostrarse en ${language.code}.`
                                                    );
                                                }
UI-010 Envío válido del formulario de contacto

¿Qué verifica?

Comprueba que un mensaje válido sea procesado mediante la API simulada, que aparezca la confirmación de envío, que el campo de mensaje quede vacío y que el botón vuelva a habilitarse. No se envían correos reales.

Código Selenium

const message = await driver.findElement(
                                                    By.id('contactMessage')
                                                );

                                                await message.sendKeys(
                                                    'Prueba automatizada Selenium: consulta de contacto válida.'
                                                );

                                                const contactButton = await driver.findElement(
                                                    By.id('contactButton')
                                                );

                                                await contactButton.click();

                                                const status = await driver.findElement(
                                                    By.id('contactStatus')
                                                );

                                                await driver.wait(
                                                    until.elementTextIs(
                                                        status,
                                                        'Mensaje enviado correctamente.'
                                                    ),
                                                    10000
                                                );

                                                assert.equal(
                                                    await status.getText(),
                                                    'Mensaje enviado correctamente.'
                                                );

                                                assert.equal(
                                                    await message.getAttribute('value'),
                                                    ''
                                                );

                                                assert.equal(
                                                    await contactButton.isEnabled(),
                                                    true
                                                );
UI-011 Validación de mensaje de contacto vacío

¿Qué verifica?

Comprueba que el formulario de contacto rechace un mensaje vacío mediante la validación HTML5. También verifica que no aparezca una confirmación de envío. No se comprueba directamente la ausencia de una solicitud HTTP.

Código Selenium

const contactButton = await driver.findElement(
                                                    By.id('contactButton')
                                                );

                                                await contactButton.click();

                                                const messageField = await driver.findElement(
                                                    By.id('contactMessage')
                                                );

                                                const isInvalid = await driver.executeScript(
                                                    'return !arguments[0].checkValidity();',
                                                    messageField
                                                );

                                                assert.equal(
                                                    isInvalid,
                                                    true,
                                                    'El campo vacío debe ser inválido según HTML5.'
                                                );

                                                const error = await driver.findElement(
                                                    By.id('contactMessageError')
                                                );

                                                const errorText = await error.getText();

                                                assert.ok(
                                                    errorText === '' ||
                                                    errorText === 'El mensaje es obligatorio.',
                                                    'No debe aparecer un mensaje inesperado.'
                                                );

                                                const status = await driver.findElement(
                                                    By.id('contactStatus')
                                                );

                                                assert.equal(
                                                    await status.getText(),
                                                    '',
                                                    'No debe mostrarse una confirmación de envío.'
                                                );
UI-015 Manejo de error HTTP 500

¿Qué verifica?

Comprueba que, ante un fallo simulado del servicio de contacto, el formulario muestre el mensaje de error correspondiente, conserve el texto ingresado y vuelva a habilitar el botón de envío. No se envían correos reales.

Código Selenium

const message = await driver.findElement(
                                                    By.id('contactMessage')
                                                );

                                                const testMessage =
                                                    'Prueba Selenium: error HTTP 500 simulado.';

                                                await message.sendKeys(testMessage);

                                                const contactButton = await driver.findElement(
                                                    By.id('contactButton')
                                                );

                                                await contactButton.click();

                                                const status = await driver.findElement(
                                                    By.id('contactStatus')
                                                );

                                                const expectedError =
                                                    'No se pudo enviar el mensaje. Intentá nuevamente más tarde.';

                                                await driver.wait(
                                                    until.elementTextIs(status, expectedError),
                                                    10000
                                                );

                                                assert.equal(
                                                    await status.getText(),
                                                    expectedError
                                                );

                                                assert.equal(
                                                    await message.getAttribute('value'),
                                                    testMessage
                                                );

                                                assert.equal(
                                                    await contactButton.isEnabled(),
                                                    true
                                                );
SEARCH Buscador global · 43 escenarios automatizados

Cobertura de la suite

Pruebas funcionales y de regresión del buscador global: coincidencias, navegación, accesibilidad, internacionalización y comportamiento de los resultados.

RF-06 · HU-005 · BDD-006

SEARCH-TC-001 Búsquedas consecutivas sin recargar

¿Qué verifica?

Verifica que el buscador permita realizar consultas consecutivas, actualice los resultados sin recargar la página, elimine los resultados anteriores y cierre el panel al limpiar la búsqueda.

Código Selenium

const escenarios = [
                                { query: 'repositorio', destination: 'index.html#github' },
                                { query: 'linkedin', destination: 'index.html#linkedin' },
                                { query: 'marketing', destination: 'cv.html#education' }
                            ];

                            for (const escenario of escenarios) {
                                await searchInput.clear();
                                await searchInput.sendKeys(escenario.query);

                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            `.portfolio-search-result[href="${escenario.destination}"]`
                                        )
                                    ),
                                    10000
                                );

                                assert.equal(await resultado.isDisplayed(), true);

                                assert.equal(
                                    await searchInput.getAttribute('value'),
                                    escenario.query
                                );
                            }

                            await searchInput.clear();

                            await driver.wait(async () => {
                                const panel = await driver.findElement(
                                    By.css('.portfolio-search-results')
                                );

                                return !(await panel.isDisplayed());
                            }, 10000);

Fragmento representativo de la prueba real. El archivo original también verifica que no permanezcan resultados de consultas anteriores.

SEARCH-TC-002 Navegación con teclado

¿Qué verifica?

Verifica que el usuario pueda buscar una sección, seleccionar un resultado mediante la flecha hacia abajo y acceder a su destino presionando Enter.

Código Selenium

await driver.get(
                                `${BASE_URL}/quality-management.html`
                            );

                            const searchInput = await driver.wait(
                                until.elementLocated(
                                    By.css('.portfolio-search-input')
                                ),
                                10000
                            );

                            // Buscar una sección conocida.
                            await searchInput.sendKeys('arquitectura');

                            // Esperar el resultado esperado.
                            const resultado = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="backend.html#arquitectura"]'
                                    )
                                ),
                                10000
                            );

                            assert.equal(await resultado.isDisplayed(), true);

                            // Seleccionar el primer resultado con ArrowDown.
                            await searchInput.sendKeys('\uE015');

                            // Navegar con Enter.
                            await searchInput.sendKeys('\uE007');

                            // Verificar el destino.
                            await driver.wait(
                                until.urlContains('backend.html#arquitectura'),
                                10000
                            );

                            assert.ok(
                                (await driver.getCurrentUrl())
                                    .endsWith('backend.html#arquitectura')
                            );

Fragmento de la prueba real que comprueba la selección mediante ArrowDown, la navegación con Enter y la llegada a la sección Arquitectura del backend.

SEARCH-TC-003 Cerrar resultados con Escape

¿Qué verifica?

Verifica que Escape cierre el panel de resultados, limpie el campo de búsqueda y actualice el estado de accesibilidad sin navegar a otra página. También comprueba que sea posible realizar una nueva búsqueda después del cierre.

Código Selenium

await driver.get(`${BASE_URL}/quality-management.html`);

                            const searchInput = await driver.wait(
                                until.elementLocated(
                                    By.css('.portfolio-search-input')
                                ),
                                10000
                            );

                            const results = await driver.findElement(
                                By.css('.portfolio-search-results')
                            );

                            // Buscar y comprobar que aparecen resultados.
                            await searchInput.sendKeys('arquitectura');

                            await driver.wait(
                                until.elementIsVisible(results),
                                10000
                            );

                            assert.equal(await results.isDisplayed(), true);

                            // Cerrar mediante Escape.
                            await searchInput.sendKeys('\uE00C');

                            await driver.wait(
                                until.elementIsNotVisible(results),
                                10000
                            );

                            assert.equal(await results.isDisplayed(), false);

                            // Verificar limpieza del campo y accesibilidad.
                            assert.equal(
                                await searchInput.getAttribute('value'),
                                ''
                            );

                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'),
                                'false'
                            );

                            // Comprobar que no hubo navegación.
                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.includes('quality-management.html')
                            );

                            // Realizar una nueva búsqueda.
                            await searchInput.sendKeys('persistencia');

                            await driver.wait(
                                until.elementIsVisible(results),
                                10000
                            );

                            const nuevoResultado = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="backend.html#persistencia"]'
                                    )
                                ),
                                10000
                            );

                            assert.equal(await nuevoResultado.isDisplayed(), true);

                            // Verificar que el panel volvió a abrirse.
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'),
                                'true'
                            );

Fragmento de la prueba real que verifica el cierre con Escape, la limpieza del campo, la ausencia de navegación, los estados aria-expanded y la recuperación del buscador mediante una nueva consulta.

SEARCH-TC-004 Búsqueda sin resultados ES/EN/PT

¿Qué verifica?

Comprueba que las búsquedas sin coincidencias muestren el mensaje correspondiente en español, inglés y portugués, sin generar enlaces de resultados.

Código Selenium

const escenarios = [
                                { language: 'es', expected: 'No se encontraron resultados.' },
                                { language: 'en', expected: 'No results found.' },
                                { language: 'pt', expected: 'Nenhum resultado encontrado.' }
                            ];

                            for (const escenario of escenarios) {
                                await driver.executeScript(
                                    'document.documentElement.lang = arguments[0]',
                                    escenario.language
                                );

                                await searchInput.clear();
                                await searchInput.sendKeys('zzzxxyy123456');

                                await driver.wait(async () => {
                                    const mensajes = await driver.findElements(
                                        By.css('.portfolio-search-empty')
                                    );

                                    return mensajes.length > 0 &&
                                        await mensajes[0].getText() === escenario.expected;
                                }, 10000);

                                const enlaces = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                assert.equal(enlaces.length, 0);
                            }

Fragmento de la prueba real que comprueba el mensaje localizado y la ausencia de enlaces para cada idioma.

SEARCH-TC-005 Búsqueda con y sin acentos

¿Qué verifica?

Comprueba que una búsqueda encuentre la misma sección tanto si el usuario escribe palabras acentuadas como si omite los acentos.

Código Selenium

const escenarios = [
                                'cierre de épica',
                                'cierre de epica'
                            ];

                            for (const query of escenarios) {
                                await searchInput.clear();
                                await searchInput.sendKeys(query);

                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="quality-management.html#cierre-epica"]'
                                        )
                                    ),
                                    10000
                                );

                                assert.equal(
                                    await resultado.isDisplayed(),
                                    true,
                                    `No aparece el resultado para: ${query}`
                                );
                            }

Fragmento de la prueba real que verifica el mismo destino para las consultas con y sin acentos.

SEARCH-TC-006 Resultados traducidos ES/EN/PT

¿Qué verifica?

Verifica que el título y la descripción del resultado Arquitectura de la API coincidan exactamente con las traducciones esperadas en los tres idiomas.

Código Selenium

const idiomas = ['es', 'en', 'pt'];

                            const traduccionesEsperadas = {
                                es: {
                                    titulo: 'Arquitectura de la API',
                                    descripcion: 'Endpoints implementados con Node.js y Express'
                                },
                                en: {
                                    titulo: 'API architecture',
                                    descripcion: 'Endpoints implemented with Node.js and Express'
                                },
                                pt: {
                                    titulo: 'Arquitetura da API',
                                    descripcion: 'Endpoints implementados com Node.js e Express'
                                }
                            };

                            for (const idioma of idiomas) {
                                await driver.executeScript(
                                    'document.documentElement.lang = arguments[0]',
                                    idioma
                                );

                                await searchInput.clear();
                                await searchInput.sendKeys('arquitectura');

                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                const titulo = await resultado.findElement(
                                    By.css('strong')
                                ).getText();

                                const descripcion = await resultado.findElement(
                                    By.css('small')
                                ).getText();

                                assert.ok(titulo.trim().length > 0);
                                assert.ok(descripcion.trim().length > 0);

                                assert.equal(
                                    titulo,
                                    traduccionesEsperadas[idioma].titulo
                                );

                                assert.equal(
                                    descripcion,
                                    traduccionesEsperadas[idioma].descripcion
                                );
                            }

Fragmento de la prueba real que compara títulos y descripciones con los textos esperados en ES, EN y PT.

SEARCH-TC-007 Cierre y reapertura por foco

¿Qué verifica?

Verifica que el panel se cierre al hacer clic fuera del buscador, conserve la consulta y vuelva a mostrar los resultados al recuperar el foco.

Código Selenium

await searchInput.sendKeys('arquitectura');

                            await driver.wait(
                                until.elementIsVisible(results),
                                10000
                            );

                            const zonaExterna = await driver.findElement(
                                By.css('h1')
                            );

                            await zonaExterna.click();

                            await driver.wait(
                                until.elementIsNotVisible(results),
                                10000
                            );

                            assert.equal(await results.isDisplayed(), false);

                            assert.equal(
                                await searchInput.getAttribute('value'),
                                'arquitectura',
                                'El clic externo eliminó el texto de búsqueda'
                            );

                            await searchInput.click();

                            await driver.wait(
                                until.elementIsVisible(results),
                                10000
                            );

                            const resultado = await driver.findElement(
                                By.css(
                                    '.portfolio-search-result[href="backend.html#arquitectura"]'
                                )
                            );

                            assert.equal(await resultado.isDisplayed(), true);

Fragmento de la prueba real que verifica el cierre mediante clic externo, la conservación del texto y la reapertura al recuperar el foco.

SEARCH-TC-008 Navegación con ArrowUp y ArrowDown

¿Qué verifica?

Comprueba el orden de los resultados de QA y la navegación entre ellos mediante las flechas del teclado, seguida de la apertura con Enter.

Código Selenium

await searchInput.sendKeys('qa');

                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 2;
                            }, 10000);

                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            const primero = resultados[0];
                            const segundo = resultados[1];

                            assert.match(
                                await primero.getText(),
                                /evidencia verificable/i
                            );

                            assert.match(
                                await segundo.getText(),
                                /especialidades/i
                            );

                            await searchInput.sendKeys('\uE015');
                            await searchInput.sendKeys('\uE015');
                            await searchInput.sendKeys('\uE013');
                            await searchInput.sendKeys('\uE007');

                            await driver.wait(
                                until.urlContains('qa.html'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(currentUrl.includes('qa.html'));

Fragmento de la prueba real que utiliza ArrowDown, ArrowUp y Enter para seleccionar y abrir el resultado correspondiente a QA.

SEARCH-TC-009 Abrir segundo resultado con teclado

¿Qué verifica?

Verifica que el usuario pueda desplazar el foco hasta el segundo resultado, abrirlo con Enter y llegar a la sección Especialidades.

Código Selenium

await searchInput.sendKeys('qa');

                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 2;
                            }, 10000);

                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            assert.match(
                                await resultados[1].getText(),
                                /especialidades/i
                            );

                            await searchInput.sendKeys('\uE015');

                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-0';
                                `);
                            }, 10000);

                            const primerResultado = await driver.switchTo().activeElement();

                            await primerResultado.sendKeys('\uE015');

                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-1';
                                `);
                            }, 10000);

                            const segundoResultado = await driver.switchTo().activeElement();

                            await segundoResultado.sendKeys('\uE007');

                            await driver.wait(
                                until.urlContains('index.html#specialties'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.endsWith('index.html#specialties')
                            );

Fragmento de la prueba real que verifica el foco del primer y segundo resultado y la navegación exacta a index.html#specialties.

SEARCH-TC-010 Búsqueda con espacios adicionales

¿Qué verifica?

Comprueba que los espacios al inicio y al final de una consulta no impidan encontrar un resultado ni navegar correctamente a su destino.

Código Selenium

await searchInput.sendKeys('   arquitectura   ');

                            const resultado = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="backend.html#arquitectura"]'
                                    )
                                ),
                                10000
                            );

                            assert.equal(
                                await resultado.isDisplayed(),
                                true,
                                'El resultado de arquitectura no aparece'
                            );

                            await resultado.click();

                            await driver.wait(
                                until.urlContains('backend.html#arquitectura'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.endsWith('backend.html#arquitectura')
                            );

Fragmento de la prueba real que comprueba la búsqueda con espacios adicionales y la navegación al destino exacto de Arquitectura del backend.

SEARCH-TC-011 Búsqueda sin distinguir mayúsculas y minúsculas

¿Qué verifica?

Verifica que arquitectura, ARQUITECTURA y ArQuItEcTuRa encuentren el mismo resultado.

Código Selenium

const consultas = [
                                'arquitectura',
                                'ARQUITECTURA',
                                'ArQuItEcTuRa'
                            ];

                            for (const consulta of consultas) {

                                // Limpiar la consulta anterior.
                                await searchInput.clear();

                                // Ingresar la nueva consulta.
                                await searchInput.sendKeys(consulta);

                                // Esperar el resultado correspondiente.
                                const resultado = await driver.wait(async () => {
                                    const elementos = await driver.findElements(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    );

                                    if (elementos.length === 0) return false;

                                    return await elementos[0].isDisplayed()
                                        ? elementos[0]
                                        : false;
                                }, 10000);

                                assert.equal(
                                    await resultado.isDisplayed(),
                                    true,
                                    `No se encontró arquitectura con: ${consulta}`
                                );

                            }

Compara la visibilidad del destino esperado para tres variantes de capitalización.

SEARCH-TC-012 Limpiar consulta y cerrar resultados

¿Qué verifica?

Comprueba que borrar toda la consulta cierre los resultados, deje el campo vacío y cambie aria-expanded a false.

Código Selenium

// 1. Realizar una búsqueda válida.
                            await searchInput.sendKeys('arquitectura');

                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length > 0 &&
                                    await resultados[0].isDisplayed();
                            }, 10000);

                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'),
                                'true'
                            );

                            // 2. Borrar completamente la consulta.
                            await searchInput.clear();

                            // 3. Esperar el cierre del desplegable.
                            await driver.wait(async () => {
                                const expanded = await searchInput.getAttribute('aria-expanded');

                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                const visibles = [];

                                for (const resultado of resultados) {
                                    if (await resultado.isDisplayed()) {
                                        visibles.push(resultado);
                                    }
                                }

                                return expanded === 'false' && visibles.length === 0;
                            }, 10000);

                            // 4. Verificar el campo vacío.
                            assert.equal(
                                await searchInput.getAttribute('value'),
                                ''
                            );

Verifica la ausencia de resultados visibles y el estado de accesibilidad después de limpiar el campo.

SEARCH-TC-013 Búsqueda con caracteres especiales

¿Qué verifica?

Comprueba que una consulta compuesta por caracteres especiales muestre el mensaje sin resultados en español y no genere enlaces seleccionables.

Código Selenium

// 1. Establecer el idioma español.
                            await driver.executeScript(`
                                document.documentElement.lang = 'es';
                            `);

                            // 2. Introducir caracteres especiales.
                            await searchInput.sendKeys('@@@###%%%');

                            // 3. Esperar el mensaje sin resultados.
                            const mensaje = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-empty')),
                                10000
                            );

                            await driver.wait(
                                until.elementIsVisible(mensaje),
                                10000
                            );

                            assert.equal(
                                (await mensaje.getText()).trim(),
                                'No se encontraron resultados.'
                            );

                            // 4. Comprobar que no existen resultados seleccionables.
                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            assert.equal(
                                resultados.length,
                                0,
                                'No deberían existir resultados para esta consulta'
                            );

Verifica el mensaje esperado y que la lista de enlaces permanezca vacía.

SEARCH-TC-014 Actualización de resultados al cambiar consulta

¿Qué verifica?

Verifica que al sustituir arquitectura por linkedin aparezca el nuevo resultado, desaparezca el anterior y se conserve la consulta actual.

Código Selenium

// 1. Buscar arquitectura.
                            await searchInput.sendKeys('arquitectura');

                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css(
                                        '.portfolio-search-result[href="backend.html#arquitectura"]'
                                    )
                                );

                                return resultados.length > 0 && await resultados[0].isDisplayed();
                            }, 10000);


                            // 2. Sustituir la consulta sin recargar.
                            await searchInput.clear();
                            await searchInput.sendKeys('linkedin');

                            // 3. Esperar el resultado de LinkedIn.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css(
                                        '.portfolio-search-result[href="index.html#linkedin"]'
                                    )
                                );

                                return resultados.length > 0 && await resultados[0].isDisplayed();
                            }, 10000);

                            // 4. Comprobar que desapareció el resultado anterior.
                            const resultadosAnteriores = await driver.findElements(
                                By.css(
                                    '.portfolio-search-result[href="backend.html#arquitectura"]'
                                )
                            );

                            assert.equal(
                                resultadosAnteriores.length,
                                0,
                                'La búsqueda anterior continúa en los resultados'
                            );

                            // 5. Verificar la consulta actual.
                            assert.equal(
                                await searchInput.getAttribute('value'),
                                'linkedin'
                            );

Comprueba la actualización de resultados sin recargar la página y la eliminación de coincidencias anteriores.

SEARCH-TC-015 Seleccionar segundo resultado con clic

¿Qué verifica?

Comprueba que el segundo resultado de QA sea Especialidades y que al hacer clic se abra la sección con el ancla correcta.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar el resultado Especialidades.
                            const resultado = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="index.html#specialties"]'
                                    )
                                ),
                                10000
                            );

                            await driver.wait(
                                until.elementIsVisible(resultado),
                                10000
                            );

                            // 3. Verificar que es el segundo resultado.
                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            assert.equal(
                                await resultados[1].getAttribute('href'),
                                `${BASE_URL}/index.html#specialties`
                            );

                            // 4. Seleccionar Especialidades mediante clic.
                            await resultado.click();

                            // 5. Verificar la navegación.
                            await driver.wait(
                                until.urlContains('index.html#specialties'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.endsWith('index.html#specialties'),
                                `Destino incorrecto: ${currentUrl}`
                            );


                            // 6. Verificar que existe la sección de destino.
                            const seccion = await driver.wait(
                                until.elementLocated(By.id('specialties')),
                                10000
                            );

                            assert.ok(
                                seccion,
                                'No se encontró la sección Especialidades'
                            );

                            // 7. Verificar que la URL conserva el ancla correcta.
                            const hash = await driver.executeScript(
                                'return window.location.hash;'
                            );

                            assert.equal(
                                hash,
                                '#specialties',
                                'El ancla de navegación es incorrecta'
                            );

Verifica posición, URL, existencia de la sección y hash #specialties.

SEARCH-TC-016 Buscar después de navegar a otra página

¿Qué verifica?

Verifica que el buscador funcione tras navegar de Gestión de calidad a Backend y permita regresar mediante otra búsqueda.

Código Selenium

// 1. Abrir Gestión de calidad.
                            await driver.get(`${BASE_URL}/quality-management.html`);

                            let searchInput = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-input')),
                                10000
                            );

                            // 2. Buscar arquitectura.
                            await searchInput.sendKeys('arquitectura');

                            const arquitectura = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="backend.html#arquitectura"]'
                                    )
                                ),
                                10000
                            );

                            await driver.wait(
                                until.elementIsVisible(arquitectura),
                                10000
                            );

                            // 3. Navegar a Backend.
                            await arquitectura.click();

                            await driver.wait(
                                until.urlContains('backend.html#arquitectura'),
                                10000
                            );


                            // 4. Localizar el buscador en la nueva página.
                            searchInput = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-input')),
                                10000
                            );

                            // 5. Realizar una nueva búsqueda.
                            await searchInput.sendKeys('trazabilidad');

                            // 6. Verificar el resultado.
                            const trazabilidad = await driver.wait(
                                until.elementLocated(
                                    By.css(
                                        '.portfolio-search-result[href="quality-management.html#trazabilidad"]'
                                    )
                                ),
                                10000
                            );

                            await driver.wait(
                                until.elementIsVisible(trazabilidad),
                                10000
                            );


                            // 7. Navegar nuevamente a Gestión de calidad.
                            await trazabilidad.click();

                            await driver.wait(
                                until.urlContains('quality-management.html#trazabilidad'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.endsWith('quality-management.html#trazabilidad'),
                                `Destino incorrecto: ${currentUrl}`
                            );

Comprueba las dos navegaciones y la disponibilidad del buscador en la nueva página.

SEARCH-TC-017 Verificar orden de resultados

¿Qué verifica?

Comprueba que la búsqueda QA presente primero la página QA y después la sección Especialidades.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar al menos dos resultados visibles.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 2 &&
                                    await resultados[0].isDisplayed() &&
                                    await resultados[1].isDisplayed();
                            }, 10000);

                            // 3. Recuperar los resultados en orden.
                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            // 4. Verificar el primer destino.
                            assert.ok(
                                (await resultados[0].getAttribute('href'))
                                    .endsWith('/qa.html'),
                                'El primer resultado debería ser QA'
                            );

                            // 5. Verificar el segundo destino.
                            assert.ok(
                                (await resultados[1].getAttribute('href'))
                                    .endsWith('/index.html#specialties'),
                                'El segundo resultado debería ser Especialidades'
                            );

Verifica el orden de los dos primeros destinos mediante sus enlaces.

SEARCH-TC-018 Navegación con Tab y Enter

¿Qué verifica?

Verifica que Tab enfoque el primer resultado y Enter lo abra; contempla el foco intermedio en el contenedor desplazable de Firefox.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar el primer resultado.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length > 0 &&
                                    await resultados[0].isDisplayed();
                            }, 10000);

                            // 3. Navegar con Tab desde el buscador.
                            await searchInput.sendKeys('\uE004');

                            let elementoActivo = await driver.switchTo().activeElement();

                            // Firefox puede enfocar primero el contenedor desplazable.
                            const esContenedor = await driver.executeScript(`
                                return document.activeElement?.id ===
                                    'portfolio-search-results';
                            `);

                            if (esContenedor) {
                                await elementoActivo.sendKeys('\uE004');
                            }

                            // 4. Verificar que Tab llega al primer resultado.
                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.classList.contains(
                                        'portfolio-search-result'
                                    ) === true;
                                `);
                            }, 10000);

                            const resultadoActivo = await driver.switchTo().activeElement();

                            assert.ok(
                                (await resultadoActivo.getAttribute('href'))
                                    .endsWith('/qa.html'),
                                'Tab no seleccionó el primer resultado esperado'
                            );


                            // 5. Abrir el resultado con Enter.
                            await resultadoActivo.sendKeys('\uE007');

                            // 6. Verificar la navegación.
                            await driver.wait(
                                until.urlContains('/qa.html'),
                                10000
                            );

                            const currentUrl = await driver.getCurrentUrl();

                            assert.ok(
                                currentUrl.endsWith('/qa.html'),
                                `Destino incorrecto: ${currentUrl}`
                            );

Comprueba el foco, el destino QA y el comportamiento específico contemplado para Firefox.

SEARCH-TC-019 Navegación inversa con Shift + Tab

¿Qué verifica?

Verifica que Tab avance hasta el segundo resultado, Shift+Tab regrese al primero y Enter abra la página QA.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar al menos dos resultados.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 2 &&
                                    await resultados[1].isDisplayed();
                            }, 10000);

                            // 3. Avanzar al primer resultado con Tab.
                            await searchInput.sendKeys('\uE004');

                            let elementoActivo = await driver.switchTo().activeElement();

                            // Firefox puede enfocar primero el contenedor desplazable.
                            const esContenedor = await driver.executeScript(`
                                return document.activeElement?.id ===
                                    'portfolio-search-results';
                            `);

                            if (esContenedor) {
                                await elementoActivo.sendKeys('\uE004');
                            }

                            // Verificar que el foco llegue al primer resultado.
                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-0';
                                `);
                            }, 10000);

                            // 4. Avanzar al segundo resultado con Tab.
                            let resultadoActivo = await driver.switchTo().activeElement();

                            await resultadoActivo.sendKeys('\uE004');

                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-1';
                                `);
                            }, 10000);


                            // 5. Regresar al primero con Shift + Tab.
                            resultadoActivo = await driver.switchTo().activeElement();

                            await resultadoActivo.sendKeys('\uE008', '\uE004');

                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-0';
                                `);
                            }, 10000);


                            // 6. Abrir el primer resultado con Enter.
                            resultadoActivo = await driver.switchTo().activeElement();

                            await resultadoActivo.sendKeys('\uE007');

                            await driver.wait(
                                until.urlContains('/qa.html'),
                                10000
                            );

                            assert.ok(
                                (await driver.getCurrentUrl()).endsWith('/qa.html'),
                                'La navegación no llegó a QA'
                            );

Comprueba el foco en ambos resultados y el regreso al primero antes de navegar.

SEARCH-TC-020 Recorrido de resultados con flechas

¿Qué verifica?

Verifica el recorrido del primer al tercer resultado con ArrowDown y el regreso al primero con ArrowUp, sin navegar.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar al menos tres resultados.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 3 &&
                                    await resultados[2].isDisplayed();
                            }, 10000);

                            // 3. Seleccionar el primer resultado.
                            await searchInput.sendKeys('\uE015');

                            const verificarFoco = async (indice) => {
                                await driver.wait(async () => {
                                    return await driver.executeScript(
                                        'return document.activeElement?.id;',
                                    ) === `portfolio-search-result-${indice}`;
                                }, 10000);
                            };

                            await verificarFoco(0);

                            // 4. Avanzar al segundo resultado.
                            let activo = await driver.switchTo().activeElement();
                            await activo.sendKeys('\uE015');

                            await verificarFoco(1);

                            // 5. Avanzar al tercer resultado.
                            activo = await driver.switchTo().activeElement();
                            await activo.sendKeys('\uE015');

                            await verificarFoco(2);

                            // 6. Regresar al segundo resultado.
                            activo = await driver.switchTo().activeElement();
                            await activo.sendKeys('\uE013');

                            await verificarFoco(1);

                            // 7. Regresar al primer resultado.
                            activo = await driver.switchTo().activeElement();
                            await activo.sendKeys('\uE013');

                            await verificarFoco(0);

                            // 8. Verificar que seguimos en la misma página.
                            assert.ok(
                                (await driver.getCurrentUrl())
                                    .includes('/quality-management.html'),
                                'La navegación cambió de página inesperadamente'
                            );

Comprueba cada cambio de foco y que la URL permanezca en Gestión de calidad.

SEARCH-TC-021 Escape desde un resultado seleccionado

¿Qué verifica?

Verifica que Escape cierre los resultados cuando el foco está en un enlace, actualice aria-expanded y no provoque navegación.

Código Selenium

// 1. Buscar QA.
                            await searchInput.sendKeys('qa');

                            // 2. Esperar resultados.
                            await driver.wait(async () => {
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                return resultados.length >= 2 &&
                                    await resultados[0].isDisplayed();
                            }, 10000);

                            // 3. Seleccionar el primer resultado con ArrowDown.
                            await searchInput.sendKeys('\uE015');

                            await driver.wait(async () => {
                                return await driver.executeScript(`
                                    return document.activeElement?.id ===
                                        'portfolio-search-result-0';
                                `);
                            }, 10000);

                            // 4. Presionar Escape desde el resultado seleccionado.
                            const resultadoActivo = await driver.switchTo().activeElement();

                            await resultadoActivo.sendKeys('\uE00C');

                            // 5. Verificar el cierre del desplegable.
                            await driver.wait(async () => {
                                return await searchInput.getAttribute('aria-expanded') === 'false';
                            }, 10000);

                            // 6. Verificar que no quedan resultados visibles.
                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );

                            for (const resultado of resultados) {
                                assert.equal(
                                    await resultado.isDisplayed(),
                                    false,
                                    'El desplegable conserva resultados visibles'
                                );
                            }

                            // 7. Verificar que no hubo navegación.
                            assert.ok(
                                (await driver.getCurrentUrl())
                                    .includes('/quality-management.html'),
                                'Escape provocó una navegación inesperada'
                            );

Comprueba el cierre desde un resultado enfocado, la ausencia de enlaces visibles y la permanencia en la página.

SEARCH-TC-022 Nueva búsqueda después de Escape desde un resultado

¿Qué verifica?

Verifica que, tras cerrar los resultados con Escape desde un enlace seleccionado, el buscador permita escribir otra consulta, muestre el resultado de Persistencia y actualice aria-expanded.

Código Selenium

// 1. Buscar QA.
                                await searchInput.sendKeys('qa');

                                // 2. Esperar el primer resultado.
                                await driver.wait(async () => {
                                    const resultados = await driver.findElements(
                                        By.css('.portfolio-search-result')
                                    );

                                    return resultados.length > 0 &&
                                        await resultados[0].isDisplayed();
                                }, 10000);

                                // 3. Seleccionar el primer resultado.
                                await searchInput.sendKeys('\uE015');

                                await driver.wait(async () => {
                                    return await driver.executeScript(`
                                        return document.activeElement?.id ===
                                            'portfolio-search-result-0';
                                    `);
                                }, 10000);

                                // 4. Cerrar mediante Escape desde el resultado.
                                const activo = await driver.switchTo().activeElement();
                                await activo.sendKeys('\uE00C');

                                await driver.wait(async () => {
                                    return await searchInput.getAttribute('aria-expanded') === 'false';
                                }, 10000);

                                // 5. Volver al campo de búsqueda y escribir otra consulta.
                                await searchInput.clear();
                                await searchInput.sendKeys('persistencia');

                                // 6. Comprobar que aparece el nuevo resultado.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#persistencia"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

                                assert.equal(
                                    await searchInput.getAttribute('value'),
                                    'persistencia'
                                );

Fragmento real que comprueba el cierre con Escape desde un resultado y la recuperación de una nueva búsqueda.

SEARCH-TC-023 Estado aria-expanded del buscador

¿Qué verifica?

Comprueba que aria-expanded sea false inicialmente, cambie a true al mostrar resultados, vuelva a false al limpiar y regrese a true con otra búsqueda.

Código Selenium

// 1. Verificar el estado inicial.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'false',
                                    'El buscador debería comenzar cerrado'
                                );

                                // 2. Introducir una consulta válida.
                                await searchInput.sendKeys('arquitectura');

                                await driver.wait(async () => {
                                    return await searchInput.getAttribute('aria-expanded') === 'true';
                                }, 10000);

                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                assert.ok(
                                    resultados.length > 0,
                                    'No aparecen resultados al abrir el buscador'
                                );

                                // 3. Limpiar la consulta.
                                await searchInput.clear();

                                await driver.wait(async () => {
                                    return await searchInput.getAttribute('aria-expanded') === 'false';
                                }, 10000);

                                // 4. Realizar otra búsqueda.
                                await searchInput.sendKeys('persistencia');

                                await driver.wait(async () => {
                                    return await searchInput.getAttribute('aria-expanded') === 'true';
                                }, 10000);

Fragmento real que verifica la secuencia de estados de accesibilidad del buscador.

SEARCH-TC-024 Integridad de enlaces y títulos

¿Qué verifica?

Verifica que cada resultado de la búsqueda QA tenga un enlace no vacío, texto visible y un destino dentro del portfolio.

Código Selenium

// 1. Realizar la búsqueda.
                                await searchInput.sendKeys('qa');

                                // 2. Esperar resultados visibles.
                                await driver.wait(async () => {
                                    const resultados = await driver.findElements(
                                        By.css('.portfolio-search-result')
                                    );

                                    return resultados.length > 0 &&
                                        await resultados[0].isDisplayed();
                                }, 10000);

                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                // 3. Verificar cada resultado.
                                for (const [indice, resultado] of resultados.entries()) {

                                    const href = await resultado.getAttribute('href');
                                    const texto = (await resultado.getText()).trim();

                                    assert.ok(
                                        href && href.trim().length > 0,
                                        `El resultado ${indice + 1} no tiene enlace`
                                    );

                                    assert.ok(
                                        texto.length > 0,
                                        `El resultado ${indice + 1} no tiene texto visible`
                                    );

                                    assert.ok(
                                        href.startsWith(BASE_URL),
                                        `El resultado ${indice + 1} apunta fuera del portfolio: ${href}`
                                    );
                                }

Fragmento real que recorre todos los resultados y valida sus enlaces y textos.

SEARCH-TC-025 Resultados sin destinos duplicados

¿Qué verifica?

Comprueba que los resultados de la búsqueda QA no contengan enlaces que apunten al mismo destino.

Código Selenium

// 1. Buscar QA.
                                await searchInput.sendKeys('qa');

                                // 2. Esperar resultados visibles.
                                await driver.wait(async () => {
                                    const resultados = await driver.findElements(
                                        By.css('.portfolio-search-result')
                                    );

                                    return resultados.length > 0 &&
                                        await resultados[0].isDisplayed();
                                }, 10000);

                                // 3. Recuperar los destinos.
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                const destinos = [];

                                for (const resultado of resultados) {
                                    destinos.push(await resultado.getAttribute('href'));
                                }

                                // 4. Comparar destinos originales y únicos.
                                const destinosUnicos = new Set(destinos);

                                assert.equal(
                                    destinosUnicos.size,
                                    destinos.length,
                                    'Se encontraron destinos duplicados en los resultados'
                                );

Fragmento real que compara la cantidad de destinos con la cantidad de destinos únicos.

SEARCH-TC-026 Eliminar resultados anteriores sin coincidencias

¿Qué verifica?

Comprueba que, al sustituir una búsqueda válida por otra sin coincidencias, desaparezcan los enlaces anteriores y aparezca el mensaje en español.

Código Selenium

// 1. Establecer español.
                                await driver.executeScript(
                                    "document.documentElement.lang = 'es';"
                                );

                                // 2. Realizar una búsqueda con resultados.
                                await searchInput.sendKeys('qa');

                                await driver.wait(async () => {
                                    const resultados = await driver.findElements(
                                        By.css('.portfolio-search-result')
                                    );

                                    return resultados.length > 0 &&
                                        await resultados[0].isDisplayed();
                                }, 10000);

                                // 3. Sustituir por una consulta sin coincidencias.
                                await searchInput.clear();
                                await searchInput.sendKeys('zzzxxyy123456');

                                // 4. Esperar el mensaje sin resultados.
                                await driver.wait(async () => {
                                    const mensajes = await driver.findElements(
                                        By.css('.portfolio-search-empty')
                                    );

                                    return mensajes.length > 0 &&
                                        await mensajes[0].isDisplayed();
                                }, 10000);

                                // 5. Comprobar el mensaje.
                                const mensaje = await driver.findElement(
                                    By.css('.portfolio-search-empty')
                                );

                                assert.equal(
                                    (await mensaje.getText()).trim(),
                                    'No se encontraron resultados.'
                                );

                                // 6. Verificar que desaparecieron los enlaces anteriores.
                                const resultados = await driver.findElements(
                                    By.css('.portfolio-search-result')
                                );

                                assert.equal(
                                    resultados.length,
                                    0,
                                    'Permanecen resultados de la búsqueda anterior'
                                );

Fragmento real que verifica la eliminación de resultados previos y el mensaje sin coincidencias.

SEARCH-TC-027 Recuperación después de una búsqueda sin resultados

¿Qué verifica?

Verifica que, después de una consulta sin coincidencias, una búsqueda válida vuelva a mostrar Arquitectura, oculte el mensaje anterior y abra el panel.

Código Selenium

// 1. Buscar un término inexistente.
                                await searchInput.sendKeys('zzzxxyy123456');

                                await driver.wait(async () => {
                                    const mensajes = await driver.findElements(
                                        By.css('.portfolio-search-empty')
                                    );

                                    return mensajes.length > 0 &&
                                        await mensajes[0].isDisplayed();
                                }, 10000);

                                // 2. Sustituir la consulta por una válida.
                                await searchInput.clear();
                                await searchInput.sendKeys('arquitectura');

                                // 3. Esperar el resultado correspondiente.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 4. Verificar que desapareció el mensaje anterior.
                                const mensajes = await driver.findElements(
                                    By.css('.portfolio-search-empty')
                                );

                                for (const mensaje of mensajes) {
                                    assert.equal(
                                        await mensaje.isDisplayed(),
                                        false,
                                        'El mensaje sin resultados continúa visible'
                                    );
                                }

                                // 5. Verificar que el desplegable está abierto.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

Fragmento real que comprueba la recuperación del buscador tras una consulta sin resultados.

SEARCH-TC-028 Búsqueda por término parcial

¿Qué verifica?

Comprueba que la consulta parcial arquitect encuentre el resultado Arquitectura y mantenga abierto el panel de búsqueda.

Código Selenium

// 1. Buscar utilizando parte del término.
                                await searchInput.sendKeys('arquitect');

                                // 2. Esperar el resultado esperado.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 3. Verificar el destino.
                                assert.ok(
                                    (await resultado.getAttribute('href'))
                                        .endsWith('/backend.html#arquitectura'),
                                    'La búsqueda parcial no encontró Arquitectura'
                                );

                                // 4. Verificar el estado del desplegable.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

Fragmento real que verifica el destino encontrado y aria-expanded para una consulta parcial.

SEARCH-TC-029 Búsqueda por descripción

¿Qué verifica?

Verifica que el término Express encuentre Arquitectura mediante el texto de su descripción y que el enlace apunte al destino esperado.

Código Selenium

// 1. Buscar un término presente en la descripción.
                                await searchInput.sendKeys('Express');

                                // 2. Esperar el resultado de Arquitectura.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 3. Verificar que el término aparece en la descripción.
                                const descripcion = await resultado.getText();

                                assert.match(
                                    descripcion,
                                    /express/i,
                                    'El término no aparece en el resultado encontrado'
                                );

                                // 4. Verificar el destino.
                                assert.ok(
                                    (await resultado.getAttribute('href'))
                                        .endsWith('/backend.html#arquitectura'),
                                    'El resultado no corresponde a Arquitectura'
                                );

Fragmento real que comprueba el texto del resultado y el destino al buscar por descripción.

SEARCH-TC-030 Búsqueda con varias palabras

¿Qué verifica?

Comprueba que la consulta arquitectura api encuentre Arquitectura de la API y que el panel permanezca abierto.

Código Selenium

// 1. Buscar utilizando varias palabras.
                                await searchInput.sendKeys('arquitectura api');

                                // 2. Esperar el resultado correspondiente.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 3. Verificar el destino.
                                assert.ok(
                                    (await resultado.getAttribute('href'))
                                        .endsWith('/backend.html#arquitectura'),
                                    'La búsqueda no encontró Arquitectura de la API'
                                );

                                // 4. Verificar que el desplegable está abierto.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

Fragmento real que verifica la coincidencia y el estado del panel para una búsqueda de varias palabras.

SEARCH-TC-031 Búsqueda con espacios internos repetidos

¿Qué verifica?

Verifica que la consulta arquitectura api, con varios espacios entre palabras, encuentre Arquitectura y mantenga el panel abierto.

Código Selenium

// 1. Buscar con varios espacios entre palabras.
                                await searchInput.sendKeys('arquitectura   api');

                                // 2. Esperar el resultado de Arquitectura.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 3. Verificar que el resultado corresponde al destino esperado.
                                assert.ok(
                                    (await resultado.getAttribute('href'))
                                        .endsWith('/backend.html#arquitectura'),
                                    'La búsqueda con espacios internos no encontró Arquitectura'
                                );

                                // 4. Verificar el estado del desplegable.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

Fragmento real que comprueba la normalización de espacios internos y el destino del resultado.

SEARCH-TC-032 Búsqueda con tabulaciones entre palabras

¿Qué verifica?

Verifica que dos tabulaciones entre arquitectura y api se conserven en el campo, permitan encontrar Arquitectura y mantengan el panel abierto.

Código Selenium

// 1. Introducir una consulta con tabulaciones.
                                // Se asigna el valor directamente para evitar que
                                // Selenium interprete TAB como navegación de foco.
                                await driver.executeScript(
                                    `
                                    const input = arguments[0];
                                    input.value = "arquitectura\\t\\tapi";
                                    input.dispatchEvent(new Event("input", { bubbles: true }));
                                    `,
                                    searchInput
                                );

                                // 2. Verificar que el valor contiene dos tabulaciones.
                                const valor = await searchInput.getAttribute('value');

                                assert.equal(
                                    valor,
                                    'arquitectura\t\tapi',
                                    'El campo no contiene las tabulaciones esperadas'
                                );

                                // 3. Esperar el resultado de Arquitectura.
                                const resultado = await driver.wait(
                                    until.elementLocated(
                                        By.css(
                                            '.portfolio-search-result[href="backend.html#arquitectura"]'
                                        )
                                    ),
                                    10000
                                );

                                await driver.wait(
                                    until.elementIsVisible(resultado),
                                    10000
                                );

                                // 4. Verificar el destino.
                                assert.ok(
                                    (await resultado.getAttribute('href'))
                                        .endsWith('/backend.html#arquitectura'),
                                    'La búsqueda con tabulaciones no encontró Arquitectura'
                                );

                                // 5. Verificar el estado del buscador.
                                assert.equal(
                                    await searchInput.getAttribute('aria-expanded'),
                                    'true'
                                );

Fragmento real que asigna las tabulaciones mediante JavaScript, dispara el evento input y comprueba valor, resultado y aria-expanded.

SEARCH-TC-033 Normalización de caracteres Unicode

¿Qué verifica?

Comprueba que una consulta con un acento Unicode combinante encuentre la sección Internacionalización y mantenga abierto el panel.

Código Selenium

const consulta = 'internacionalizacio\u0301n';
                            await searchInput.sendKeys(consulta);

                            const resultado = await driver.wait(
                                until.elementLocated(By.css(
                                    '.portfolio-search-result[href="frontend.html#internacionalizacion"]'
                                )), 10000
                            );
                            await driver.wait(until.elementIsVisible(resultado), 10000);

                            assert.ok(
                                (await resultado.getAttribute('href'))
                                    .endsWith('/frontend.html#internacionalizacion')
                            );
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'), 'true'
                            );

Fragmento de la prueba real que utiliza Unicode descompuesto, verifica el destino de frontend.html y comprueba aria-expanded.

SEARCH-TC-034 Tratamiento de saltos de línea en el input

¿Qué verifica?

Verifica que el campo HTML elimine un salto de línea, produzca el valor arquitecturaapi y muestre el mensaje sin resultados con el panel abierto.

Código Selenium

const valorReal = await driver.executeScript(`
                                const input = arguments[0];
                                input.value = "arquitectura\\napi";
                                input.dispatchEvent(new Event("input", { bubbles: true }));
                                return input.value;
                            `, searchInput);

                            assert.equal(valorReal, 'arquitecturaapi');

                            const mensaje = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-empty')), 10000
                            );
                            await driver.wait(until.elementIsVisible(mensaje), 10000);
                            assert.match(
                                await mensaje.getText(), /No se encontraron resultados/i
                            );
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'), 'true'
                            );

Fragmento de la prueba real que asigna el valor mediante JavaScript, dispara el evento input y comprueba el valor sanitizado y el mensaje.

SEARCH-TC-035 Consulta compuesta únicamente por espacios

¿Qué verifica?

Comprueba que una consulta de cinco espacios conserve su valor en el campo, pero se trate como vacía, sin resultados y con el panel oculto.

Código Selenium

await searchInput.sendKeys('     ');
                            assert.equal(
                                await searchInput.getAttribute('value'), '     '
                            );
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'), 'false'
                            );

                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );
                            assert.equal(resultados.length, 0);

                            const contenedor = await driver.findElement(
                                By.css('.portfolio-search-results')
                            );
                            assert.equal(await contenedor.getAttribute('hidden'), 'true');

Fragmento de la prueba real que verifica el valor del campo, aria-expanded, la ausencia de enlaces y el atributo hidden.

SEARCH-TC-036 Caracteres especiales combinados con texto válido

¿Qué verifica?

Verifica que agregar símbolos a una consulta válida no produzca coincidencias incorrectas y muestre el mensaje sin resultados.

Código Selenium

await searchInput.sendKeys('arquitectura@@@');

                            const mensaje = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-empty')), 10000
                            );
                            await driver.wait(until.elementIsVisible(mensaje), 10000);
                            assert.match(
                                await mensaje.getText(), /No se encontraron resultados/i
                            );

                            const resultados = await driver.findElements(
                                By.css('.portfolio-search-result')
                            );
                            assert.equal(resultados.length, 0);
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'), 'true'
                            );

Fragmento de la prueba real que busca arquitectura@@@, comprueba la ausencia de enlaces y verifica aria-expanded.

SEARCH-TC-037 Recuperación tras caracteres especiales

¿Qué verifica?

Verifica que, después de una consulta sin coincidencias con símbolos, una nueva búsqueda válida recupere resultados y elimine el mensaje anterior sin recargar.

Código Selenium

await searchInput.sendKeys('arquitectura@@@');
                            const mensaje = await driver.wait(
                                until.elementLocated(By.css('.portfolio-search-empty')), 10000
                            );
                            await driver.wait(until.elementIsVisible(mensaje), 10000);
                            assert.match(
                                await mensaje.getText(), /No se encontraron resultados/i
                            );

                            await searchInput.clear();
                            await searchInput.sendKeys('arquitectura');
                            const resultado = await driver.wait(
                                until.elementLocated(By.css(
                                    '.portfolio-search-result[href="backend.html#arquitectura"]'
                                )), 10000
                            );
                            await driver.wait(until.elementIsVisible(resultado), 10000);

                            const mensajesVacios = await driver.findElements(
                                By.css('.portfolio-search-empty')
                            );
                            assert.equal(mensajesVacios.length, 0);
                            assert.equal(
                                await searchInput.getAttribute('aria-expanded'), 'true'
                            );

Fragmento de la prueba real que sustituye arquitectura@@@ por arquitectura, comprueba el resultado y verifica que desaparezca el mensaje anterior.

SEARCH-TC-038 Navegación a Arquitectura del backend

¿Qué verifica?

Verifica que la búsqueda de «arquitectura» permita acceder a backend.html#arquitectura, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-038',
                                query: 'arquitectura',
                                destination: 'backend.html#arquitectura',
                                sectionId: 'arquitectura'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-038 y las comprobaciones de resultado, URL, sección y cabecera.

SEARCH-TC-040 Navegación a Casos de prueba

¿Qué verifica?

Verifica que la búsqueda de «casos de prueba» permita acceder a qa.html#casos-prueba, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-040',
                                query: 'casos de prueba',
                                destination: 'qa.html#casos-prueba',
                                sectionId: 'casos-prueba'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-040 y las comprobaciones de resultado, URL, sección y cabecera.

SEARCH-TC-041 Navegación a Trazabilidad

¿Qué verifica?

Verifica que la búsqueda de «trazabilidad» permita acceder a quality-management.html#trazabilidad, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-041',
                                query: 'trazabilidad',
                                destination: 'quality-management.html#trazabilidad',
                                sectionId: 'trazabilidad'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-041 y las comprobaciones de resultado, URL, sección y cabecera.

SEARCH-TC-042 Navegación a Persistencia

¿Qué verifica?

Verifica que la búsqueda de «persistencia» permita acceder a backend.html#persistencia, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-042',
                                query: 'persistencia',
                                destination: 'backend.html#persistencia',
                                sectionId: 'persistencia'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-042 y las comprobaciones de resultado, URL, sección y cabecera.

SEARCH-TC-043 Navegación a Internacionalización

¿Qué verifica?

Verifica que la búsqueda de «internacionalización» permita acceder a frontend.html#internacionalizacion, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-043',
                                query: 'internacionalización',
                                destination: 'frontend.html#internacionalizacion',
                                sectionId: 'internacionalizacion'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-043 y las comprobaciones de resultado, URL, sección y cabecera.

SEARCH-TC-044 Navegación a Regresión y bugs

¿Qué verifica?

Verifica que la búsqueda de «regresión» permita acceder a qa.html#regresion-bugs, que la sección de destino sea visible y que no quede oculta detrás de la cabecera fija.

Código Selenium

const caso = {
                                id: 'SEARCH-TC-044',
                                query: 'regresión',
                                destination: 'qa.html#regresion-bugs',
                                sectionId: 'regresion-bugs'
                            };

                            // Fragmento del test parametrizado compartido.
                            await searchInput.sendKeys(caso.query);

                            const result = await driver.wait(
                                until.elementLocated(
                                    By.css(`.portfolio-search-result[href="${caso.destination}"]`)
                                ),
                                10000
                            );
                            assert.equal(await result.isDisplayed(), true);
                            await result.click();
                            await driver.wait(until.urlContains(caso.destination), 10000);
                            assert.ok((await driver.getCurrentUrl()).endsWith(caso.destination));

                            const section = await driver.findElement(By.id(caso.sectionId));
                            assert.equal(await section.isDisplayed(), true);

                            const posicion = await driver.executeScript(`
                                const section = arguments[0];
                                const navbar = document.querySelector('.navbar');
                                return {
                                    sectionTop: section.getBoundingClientRect().top,
                                    navbarBottom: navbar ? navbar.getBoundingClientRect().bottom : 0
                                };
                            `, section);
                            assert.ok(posicion.sectionTop >= posicion.navbarBottom - 2);

Fragmento representativo del test parametrizado compartido; se muestran los datos de SEARCH-TC-044 y las comprobaciones de resultado, URL, sección y cabecera.

03. Regresión y bugs

Registro de defectos detectados, correcciones y pruebas de regresión relacionadas.

BUG-001 · Validación del teléfono

Estado histórico: Cerrado. Verificación documental: Regresión automatizada satisfactoria · 3/3 PASS

Severidad: Media

Prioridad: Alta

Requisito: FR-008

Caso relacionado: TC-012 Prueba automatizada relacionada: BUG-001 · phone-validation-boundaries.test.js · 3/3 PASS · Chrome, Firefox y Edge

Ver reporte completo

Entorno

Windows · Google Chrome · Portfolio v1.0 (dato histórico)

Windows · Google Chrome, Firefox y Edge · Regresión del 30/10/2026

Precondiciones

El usuario se encuentra en la pantalla de registro.

Pasos para reproducir

  1. Abrir la aplicación.
  2. Ingresar un nombre válido.
  3. Ingresar un apellido válido.
  4. Ingresar un email válido.
  5. Ingresar abc en el campo teléfono.
  6. Aceptar el consentimiento.
  7. Presionar «Ingresar al portfolio».

Resultado esperado

El sistema rechaza el teléfono inválido y muestra un mensaje de validación.

Resultado actual

El defecto histórico documentó que el formulario permitía continuar con un teléfono que contenía caracteres alfabéticos, utilizando abc como dato de reproducción. La regresión Selenium del 30/10/2026 verificó el rechazo del valor 12345abc, la presentación del mensaje de validación y el bloqueo del acceso al portfolio en Chrome, Firefox y Edge, con 3/3 PASS. Esta prueba confirma el comportamiento actual, pero no reconstruye por sí sola la corrección histórica del defecto.

Evidencia

Evidencia automatizada complementaria: el escenario BUG-001 del archivo phone-validation-boundaries.test.js verificó el rechazo del teléfono 12345abc en Chrome, Firefox y Edge, con 3/3 PASS. El código Selenium y las aserciones correspondientes pueden consultarse en la sección 02, Automatización con Selenium. Esta prueba forma parte de la suite telefónica completa de 33/33 PASS.

Conclusión

BUG-001 permanece cerrado según el registro histórico. La regresión Selenium del 30/10/2026 confirmó el rechazo de caracteres alfabéticos en el teléfono y el bloqueo del acceso al portfolio, con 3/3 PASS en Chrome, Firefox y Edge. La evidencia acredita el comportamiento actual, sin reconstruir la corrección histórica del defecto.

BUG-002 · Validación del nombre

Estado histórico: Cerrado. Verificación documental: Regresión automatizada satisfactoria · 3/3 PASS

Severidad histórica: Alta

Prioridad histórica: Alta

Requisito principal: FR-012 · FR-002 complementario

Prueba automatizada relacionada: BUG-002 · invalid-first-name-numeric.test.js · 3/3 PASS · Chrome, Firefox y Edge

Ver reporte completo

Entorno

"Windows · Google Chrome · Portfolio v0.1 (dato histórico)",

"Windows · Google Chrome, Firefox y Edge · Regresión del 30/10/2026",

Precondiciones

El usuario se encuentra en la pantalla de acceso.

Pasos para reproducir

  1. Ingresar sdfh567 o klsjdbg654#&%& como nombre.
  2. Completar los demás campos con datos válidos.
  3. Aceptar el consentimiento e intentar ingresar.

Resultado esperado

El sistema debe rechazar un nombre que no cumpla las reglas de validación.

Resultado actual

El registro histórico indica que el formulario permitía continuar con un nombre inválido. La regresión Selenium del 30/10/2026 confirmó que el valor sdfh567 es rechazado, se muestra el mensaje de validación y se impide el acceso al portfolio en Chrome, Firefox y Edge (3/3 PASS). Esta verificación confirma el comportamiento actual, pero no reconstruye la corrección histórica.

Evidencia

Esta evidencia respalda el comportamiento actual del formulario, pero no acredita por sí sola la reproducción del defecto original ni su corrección histórica.

Como evidencia complementaria, la prueba Selenium invalid-first-name-numeric.test.js verificó el rechazo del nombre sdfh567 en Chrome, Firefox y Edge el 30/10/2026, con 3/3 PASS. El código de la prueba puede consultarse en la sección 02.

Captura compartida con BUG-003 que muestra el rechazo de un nombre con caracteres numéricos. El campo aparece resaltado en rojo y presenta el mensaje de validación correspondiente.

Ver evidencia de BUG-002 · Validación del nombre →

BUG-003 · Validación del apellido

Estado histórico: Cerrado. Verificación documental: Regresión automatizada satisfactoria · 3/3 PASS

Severidad histórica: Alta

Prioridad histórica: Alta

Requisito principal: FR-012 · FR-002 complementario

Prueba automatizada relacionada: BUG-003 · invalid-last-name-numeric.test.js · 3/3 PASS · Chrome, Firefox y Edge

Ver reporte completo

Entorno

Windows · Google Chrome · Portfolio v0.1 (dato histórico)

"Windows · Google Chrome, Firefox y Edge · Regresión del 30/10/2026"

Precondiciones

El usuario se encuentra en la pantalla de acceso.

Pasos para reproducir

  1. Ingresar un nombre válido.
  2. Ingresar Flor567 o ddbhad&"%#3516 como apellido.
  3. Completar los demás campos con datos válidos.
  4. Aceptar el consentimiento e intentar ingresar.

Resultado esperado

El sistema debe rechazar un apellido que no cumpla las reglas de validación.

Resultado actual

El registro histórico indica que el formulario permitía continuar con un apellido inválido. La regresión Selenium del 30/10/2026 confirmó que el valor Flor567 es rechazado, se muestra el mensaje de validación y se impide el acceso al portfolio en Chrome, Firefox y Edge (3/3 PASS). Esta verificación confirma el comportamiento actual, pero no reconstruye la corrección histórica.

Evidencia

Captura compartida con BUG-002 que muestra el rechazo de un apellido que contiene caracteres numéricos. El campo aparece resaltado en rojo y presenta el mensaje de validación correspondiente.

Esta evidencia respalda el comportamiento actual del formulario, pero no acredita por sí sola la reproducción del defecto original ni su corrección histórica.

Como evidencia complementaria, la prueba Selenium invalid-last-name-numeric.test.js verificó el rechazo del apellido Flor567 en Chrome, Firefox y Edge el 30/10/2026, con 3/3 PASS. El código de la prueba puede consultarse en la sección 02.

Ver evidencia de BUG-003 · Validación del apellido →

BUG-004 · Observación de requisitos: validación del email

Estado histórico: Cerrado.

Clasificación actual: Observación de requisitos · Defecto funcional no confirmado.

Severidad histórica: Alta · Clasificación inicial, no vigente como defecto funcional.

Prioridad histórica: Alta · Clasificación inicial, no vigente como defecto funcional.

Requisito histórico: FR-003

Caso relacionado: TC-004

Prueba automatizada relacionada: invalid-email-double-at.test.js

Verificación documental: Regresión automatizada satisfactoria · 15/15 PASS

Ver reporte completo

La observación surgió durante la evaluación del formulario, al interpretar que validar un email también implicaba comprobar la existencia de la dirección o del buzón de correo. La revisión de FR-003 confirmó que el requisito especificaba únicamente la validación del formato. La diferencia se originó en la interpretación de su alcance, no en una ambigüedad demostrada de su redacción.

Entorno

Windows · Google Chrome · Portfolio v0.1 (dato histórico)

Windows · Google Chrome, Firefox y Edge · Regresión del 30/10/2026

Precondiciones

El usuario se encuentra en la pantalla de acceso.

Pasos del registro histórico

  1. Ingresar un nombre y apellido válidos.
  2. Ingresar sfghfh@sfhfhg.adhfgh como email.
  3. Completar el teléfono con un valor válido.
  4. Aceptar el consentimiento e intentar ingresar.

Resultado esperado

El sistema debe validar que la dirección de correo electrónico cumpla las reglas de formato definidas y rechazar las entradas que no las cumplan. Esta validación sintáctica no implica comprobar la existencia del dominio o del buzón de correo.

Resultado actual

La evidencia histórica muestra una dirección de correo con estructura sintáctica plausible. No demuestra que el portfolio permitiera acceder utilizando un formato inválido. No se confirmó un defecto funcional de validación de email. El registro se conserva como observación de requisitos.

Verificación posterior

La verificación posterior documentó que la interfaz identifica como inválido el correo "gabriel@@gmail.com", que contiene dos símbolos @. El campo se resalta en rojo y presenta el mensaje "Ingresá un email válido". Esta captura acredita el comportamiento visual observado. La verificación automatizada del rechazo del acceso se documenta por separado en la regresión Selenium de FR-003.

Escenarios de regresión Selenium · 30/10/2026

Cinco formatos de correo electrónico inválidos verificados en Chrome, Firefox y Edge.

  • gabriel@@gmail.com
  • gabriel@
  • gabriel@prueba
  • @gmail.com
  • gabriel@gmail.

Resultado de regresión: 15/15 PASS

La regresión verificó el rechazo de los formatos evaluados, los mensajes de validación y el bloqueo del acceso al portfolio. Estos resultados respaldan el cumplimiento de FR-003 para los escenarios ejecutados.

Evidencia

La captura documenta la validación visual posterior del correo "gabriel@@gmail.com". Se conserva el nombre original del archivo por trazabilidad histórica; la palabra "corregido" no demuestra que existiera un defecto funcional previo.

Ver evidencia de BUG-004 · Validación del email →

Conclusión documental

BUG-004 se conserva como referencia histórica y se reclasifica como una observación de requisitos. FR-003 y TC-004 mantienen su trazabilidad original. No se confirmó un defecto funcional ni corresponde atribuir una corrección a esta observación. Las 15 ejecuciones Selenium satisfactorias constituyen evidencia complementaria del comportamiento verificado.

BUG-005 · Longitud máxima del teléfono

Estado histórico: Cerrado. Verificación documental: Regresión automatizada satisfactoria · 3/3 PASS

Severidad histórica: Baja

Prioridad histórica: Alta

Requisito histórico: FR-008

Caso relacionado: TC-018 Prueba automatizada relacionada: BUG-005 · phone-validation-boundaries.test.js · 3/3 PASS · Chrome, Firefox y Edge

Ver reporte completo

Entorno

Windows · Google Chrome · Portfolio v0.1 (dato histórico)

Windows · Google Chrome, Firefox y Edge · Regresión del 30/10/2026

Precondiciones

El usuario se encuentra en la pantalla de acceso.

Pasos para reproducir

  1. Ingresar un nombre, apellido y email válidos.
  2. Ingresar un teléfono que exceda el máximo permitido.
  3. Aceptar el consentimiento e intentar ingresar.

Regresión Selenium de límites telefónicos · 30/10/2026

Se verificaron valores inferiores al mínimo, valores dentro del rango permitido y valores superiores al máximo.

  • 123456 · 6 dígitos · Rechazado · PASS
  • 1234567 · 7 dígitos · Aceptado · PASS
  • 123456789012345 · 15 dígitos · Aceptado · PASS
  • 1234567890123456 · 16 dígitos · Rechazado · PASS

Suite telefónica completa: 33/33 PASS. Escenario específico BUG-005: 3/3 PASS. Navegadores: Chrome, Firefox y Edge.

Resultado esperado

El sistema debe rechazar un teléfono que supere la longitud máxima permitida.

Resultado histórico y verificación posterior

El registro histórico indica que el formulario permitía continuar con un teléfono que superaba la longitud máxima admitida. La regresión Selenium del 30/10/2026 confirmó que el valor 1234567890123456, de 16 dígitos, es rechazado y que se impide el acceso al portfolio en Chrome, Firefox y Edge (3/3 PASS). La suite completa de validación telefónica obtuvo 33/33 PASS, incluyendo escenarios de límites inferiores, valores válidos y límites superiores. Esta verificación confirma el comportamiento actual, pero no reconstruye la corrección histórica.

Verificación posterior

El caso TC-018 registra un resultado PASS para el rechazo de teléfonos que exceden los 15 dígitos permitidos. Este resultado verifica el comportamiento documentado, pero no confirma por sí solo la trazabilidad histórica de la corrección de BUG-005.

Evidencia

Captura de verificación posterior con un teléfono de 25 dígitos, superior al máximo permitido de 15. La interfaz identifica el valor como inválido y muestra el mensaje de validación correspondiente. Esta evidencia respalda el comportamiento esperado de TC-018, sin acreditar por sí sola el defecto original ni la corrección histórica de BUG-005.

Evidencia automatizada complementaria: phone-validation-boundaries.test.js. El código de la prueba y sus resultados están documentados en la sección 02, Automatización con Selenium.

Ver evidencia de BUG-005 · TC-018 →

04. Evidencia verificable

Repositorio documental del proceso de QA: planificación, casos de prueba, resultados de ejecución y registro de defectos, con acceso a los archivos y evidencias originales del proyecto.

Casos de prueba

Especificaciones de pruebas funcionales y de API, con requisitos asociados, precondiciones, datos de entrada, pasos de ejecución y resultados esperados.

Consultar casos de prueba →

Plan de pruebas

Planificación del proceso de QA, con alcance, estrategia de pruebas, entorno de ejecución, criterios de entrada y salida, y entregables definidos para el proyecto.

Consultar plan de pruebas →

Reporte de ejecución

Historial documentado de ejecuciones funcionales, pruebas de integración, validaciones de API y regresiones automatizadas, con resultados registrados y seguimiento de las verificaciones realizadas.

TC-019 y TC-020 · Regresión multinavegador: 12/12 PASS en Chrome, Firefox y Edge.

Internacionalización CV y QA · 27/27 PASS en Chrome, Firefox y Edge.

Gestión de Calidad · Internacionalización ES/EN/PT: 66/66 PASS en Chrome, Firefox y Edge.

Formulario de acceso · Internacionalización ES/EN/PT: 15/15 PASS en Chrome, Firefox y Edge.

Laboratorio Frontend · Internacionalización ES/EN/PT: 15/15 PASS en Chrome, Firefox y Edge.

Laboratorio Backend · Internacionalización ES/EN/PT: 15/15 PASS en Chrome, Firefox y Edge.

Consultar resultados →