Seguidores

segunda-feira, 30 de junho de 2025

Dashboard de Produtividade Pessoal T2E05: BugCT1-8 Teste da correção do botão PlayTask do Dashboard

INTRODUÇÃO

Post anterior: Dashboard de Produtividade Pessoal T2E04: BugCT1-8 Teste da correção dos botões do Dashboard falhou

O objetivo deste post é apresentar um prompt para o Gemini 2.5 Pro, com o relato de falha no teste da  correção do BugCT1-8.

A falha ocorreu porque o botão "PlayTask" continua desabilitado.

Esse bug foi encontrado durante a execução do "Caso de Teste 1: Tarefa sem pausa", na temporada 2 da série Dashboard de Produtividade Pessoal.


Promp para Gemini 2.5 Pro

1 Objetivo

Olá Gemini! Corrija no App d2p, a falha que ocorreu na execução do teste realizado para validar a correção do "BugCT1-8 Botões do Dashboard não funcionam".

A falha ocorreu porque o botão "PlayTask" continua desabilitado.

2 Contexto

Arquitetura do App d2p:
  • Dashboard.html - Frontend Dashboard de Produtividade Pessoal
  • Planilha "Banco de Dados - D2P" - Backend Google Sheet
  • Código.gs - Apps Scritp para integração do Dashboard com Google Sheet

3 Dados e Fatos

Dados do Caso de Teste 1:

  • CódigoTarefa: S00.1.1.01; NomeTarefa: Tarefa 1 Teste 1; TamanhoTarefa: 5
  • CódigoTarefa: S00.1.1.02; NomeTarefa: Tarefa 2 Teste 1; TamanhoTarefa: 1
  • CódigoTarefa: S00.1.1.03; NomeTarefa: Tarefa 3 Teste 1; TamanhoTarefa: 3

Fatos que ocorreram nos testes:
  • Após adicionar uma tarefa, o botão que inicia a execução da tarefa não fica habilitado.

4 Código.gs

Código Apps Script que implementa o Frontend do App d2p, a ser corrigido pelo Gemini.

Esse código foi adicionado no momento de enviar o prompt.

5 Dashboard.html

Código Apps Script que implementa o Backend do App d2p, a ser corrigido pelo Gemini.

Esse código foi adicionado no momento de enviar o prompt.

Resposta do Gemini 2.5 Pro

Olá! Entendi o problema. A falha ocorre porque, ao adicionar uma nova tarefa, o objeto retornado pelo backend não continha o status "pending", fazendo com que a lógica do frontend mantivesse o botão "play" desabilitado.

Corrigi a função taskAdicionadaComSucesso no seu Canvas para que ela adicione as propriedades status e effectiveDuration ao novo objeto da tarefa. Isso garante que a interface seja atualizada corretamente e o botão para iniciar a tarefa seja habilitado assim que a jornada de trabalho começar.

Abaixo está o código atualizado.

CONCLUSÃO

O código Dashboard.html foi adicionado ao Apps Script, com a correção feita pelo Gemini.

No próximo post, algo muito interessante será apresentado: o próprio Gemini 2.5 Pro executará o Caso de Teste 1, conforme as especificações que forneceremos no Prompt.

Próximo post: 

domingo, 29 de junho de 2025

Dashboard de Produtividade Pessoal T2E04: BugCT1-8 Teste da correção dos botões do Dashboard falhou

INTRODUÇÃO

Post anterior: Dashboard de Produtividade Pessoal T2E03: BugCT1-8 Botões do Dashboard não funcionam

O objetivo deste post é apresentar o relato de um bug encontrado durante a execução do "Caso de Teste 1: Tarefa sem pausa", na temporada 2 da série Dashboard de Produtividade Pessoal.

Promp para Gemini 2.5 Pro

1 Objetivo

Olá Gemini! Corrija no App d2p, o bug que ocorreu na execução do teste realizado para validar a correção do "BugCT1-8 Botões do Dashboard não funcionam".

2 Contexto

A arquitetura do App d2p mudou para:
  • Frontend Dashboard de Produtividade Pessoal
  • Backend Google Sheet
  • Apps Scritp para integração do Dashboard com Google Sheet
  • Não há login no App d2p (foi removido)

3 Dados e Fatos

Dados do Caso de Teste 1:

  • CódigoTarefa: S00.1.1.01; NomeTarefa: Tarefa 1 Teste 1; TamanhoTarefa: 5
  • CódigoTarefa: S00.1.1.02; NomeTarefa: Tarefa 2 Teste 1; TamanhoTarefa: 1
  • CódigoTarefa: S00.1.1.03; NomeTarefa: Tarefa 3 Teste 1; TamanhoTarefa: 3

Fatos que ocorreram nos testes:
  • O teste funciona na opção Implantar / Testar implantações ou na opção Implantar / Gerenciar implantações, se a planilha não tiver tarefas preenchidas.
  • O teste NÃO funciona se a planilha tiver tarefas preenchidas, aparecendo no console do Chrome a mensagem abaixo:
Uncaught TypeError: Cannot read properties of null (reading 'tasks')
    at dadosCarregadosComSucesso (<anonymous>:236:28)
    at Bh (4139234525-mae_html_user_bin_i18n_mae_html_user__pt_pt.js:140:417)
    at 4139234525-mae_html_user_bin_i18n_mae_html_user__pt_pt.js:42:132
    at Ai.S (4139234525-mae_html_user_bin_i18n_mae_html_user__pt_pt.js:164:376)
    at Zd (4139234525-mae_html_user_bin_i18n_mae_html_user__pt_pt.js:76:477)
    at a (4139234525-mae_html_user_bin_i18n_mae_html_user__pt_pt.js:74:52)

4 Código.gs

Código Apps Script que implementa o Frontend do App d2p, a ser corrigido pelo Gemini.

Esse código foi adicionado no momento de enviar o prompt.

5 Dashboard.html

Código Apps Script que implementa o Backend do App d2p, a ser corrigido pelo Gemini.

Esse código foi adicionado no momento de enviar o prompt.

Resposta do Gemini 2.5 Pro

Olá! Entendi perfeitamente o problema. O erro Cannot read properties of null (reading 'tasks') acontece porque, quando a planilha tem dados (especialmente datas), o Google Apps Script pode falhar ao tentar serializar o objeto para enviá-lo ao frontend, resultando em um valor null na função de callback.

Para corrigir isso, a abordagem mais segura é converter o objeto de dados em uma string JSON no backend (Código.gs) e, em seguida, fazer o parse dessa string de volta para um objeto no frontend (Dashboard.html).

Apresento abaixo os dois arquivos com as devidas correções.

1. Correção no Backend (Código.gs)

Neste arquivo, modifiquei a função getInitialData para que ela retorne uma string JSON. Também adicionei um tratamento para garantir que as datas sejam convertidas para um formato de string padronizado (ISO), evitando problemas de serialização.

Código.gs (Corrigido)
22 de jun., 13:05

2. Correção no Frontend (Dashboard.html)

Aqui, a função dadosCarregadosComSucesso foi ajustada para receber a string JSON, fazer o parse dela e então popular o estado da aplicação. Isso resolve o erro ...reading 'tasks' of null, pois agora a função sempre receberá uma string válida para ser processada.

Dashboard.html (Corrigido)
22 de jun., 13:05

Com essas alterações, o problema de carregamento com a planilha preenchida será resolvido. O fluxo de dados entre o backend e o frontend se torna mais robusto e previsível.

CONCLUSÃO

O teste da correção foi executado com falha, porque o botão "Play Task" das tarefas continua desabilitado.

No próximo post será encaminhado outro Prompt para o Gemini 2.5 Pro corrigir.

Próximo post: Dashboard de Produtividade Pessoal T2E05: BugCT1-8 Teste da correção do botão PlayTask do Dashboard

sábado, 28 de junho de 2025

Dashboard de Produtividade Pessoal T2E03: BugCT1-8 Botões do Dashboard não funcionam

INTRODUÇÃO

Post anterior: Dashboard de Produtividade Pessoal T2E02: Caso de Teste 1 Tarefa sem pausa

O objetivo deste post é apresentar o relato de um bug encontrado durante a execução do "Caso de Teste 1: Tarefa sem pausa", na temporada 2 da série Dashboard de Produtividade Pessoal.



Promp para Gemini 2.5 Pro (Prévia)

1 Objetivo
Corrija bugs no App d2p, que ocorreram na execução do Caso de Teste 1, após a mudança da arquitetura.

2 Contexto
A arquitetura do App d2p mudou para:
  • Frontend Dashboard de Produtividade Pessoal
  • Backend Google Sheet
  • Apps Scritp para integração do Dashboard com Google Sheet
3 Dados, Fatos e Bugs
Dados do Caso de Teste 1:

  • CódigoTarefa: S00.1.1.01; NomeTarefa: Tarefa 1 Teste 1; TamanhoTarefa: 5
  • CódigoTarefa: S00.1.1.02; NomeTarefa: Tarefa 2 Teste 1; TamanhoTarefa: 1
  • CódigoTarefa: S00.1.1.03; NomeTarefa: Tarefa 3 Teste 1; TamanhoTarefa: 3

Fatos e Bugs na execução do Caso de Teste 1:
  • Ao clicar no botão Iniciar Jornada, não foi registrada a hora e nem iniciada a contagem do tempo.
  • Ao clicar no botão "Play" para iniciar a tarefa registrada, o botão não estava habilitado.
  • Ao clicar no botão para finalizar a tarefa, o botão "Finalizar" estava habilitado, mas não funcionou.

Resposta do Gemini 2.5 Pro (Prévia)

Olá! Perfeito. Agradeço pelo relatório detalhado dos bugs. Casos de teste são essenciais para encontrar problemas, e sua descrição foi muito clara.

Analisei os três bugs e a boa notícia é que todos eles têm a mesma causa raiz, o que torna a correção bem direta.

Diagnóstico da Causa Raiz

A causa principal dos três problemas está na função de inicialização do nosso script (init()) dentro do arquivo dashboard.js. Após a mudança de arquitetura e a movimentação do código, esquecemos de "conectar" os eventos de clique de alguns botões principais (como "Iniciar Jornada") às suas respectivas funções JavaScript.

Isso gerou um efeito dominó:

  1. Bug 1 (Jornada não inicia): O botão "Iniciar Jornada" não tinha seu addEventListener registrado. Por isso, ao clicar, nada acontecia.
  2. Bug 2 (Botão "Play" desabilitado): O botão para iniciar uma tarefa só é habilitado após o início da jornada (state.workday.startTime precisa ter um valor). Como a jornada nunca iniciava, os botões de tarefa permaneciam desabilitados.
  3. Bug 3 (Finalizar não funciona): O fluxo para testar o botão "Finalizar" (btnStopTask) estava quebrado porque não era possível iniciar uma tarefa corretamente. Além disso, o listener do botão de pausa/retomar também estava faltando, o que prejudicaria a interação.

Solução

A solução é garantir que todos os botões da interface tenham seus addEventListener corretamente registrados na função init() do dashboard.js.

Abaixo, forneço a versão corrigida e completa do arquivo dashboard.js. Ele contém a lógica de inicialização correta, que resolve os três bugs de uma só vez.


Código Corrigido para dashboard.js

Copie todo o código abaixo e substitua completamente o conteúdo do seu arquivo dashboard.js atual. As correções estão destacadas com comentários.

JavaScript
document.addEventListener('DOMContentLoaded', function() {
    // ---- VERIFICAÇÃO DE LOGIN E AUTENTICAÇÃO ----
    // Esta parte permanece a mesma, garantindo que o usuário esteja logado.
    const nomeUsuario = localStorage.getItem('usuarioNome');
    const emailUsuario = localStorage.getItem('usuarioEmail');

    if (!nomeUsuario || !emailUsuario) {
        alert("Acesso negado. Por favor, faça o login.");
        window.location.href = 'index.html';
        return;
    }

    document.getElementById('welcome-message').textContent = `Logado como: ${nomeUsuario}`;

    document.getElementById('logoutButton').addEventListener('click', () => {
        if (typeof google !== 'undefined' && google.accounts && google.accounts.id) {
            google.accounts.id.disableAutoSelect();
        }
        localStorage.clear();
        window.location.href = 'index.html';
    });

    // ---- LÓGICA DO DASHBOARD ----
    
    // --- ELEMENTOS DO DOM ---
    const loader = document.getElementById('loader');
    const dashboardContent = document.getElementById('dashboard-content');
    const formAddTask = document.getElementById('formAddTask');
    const taskListEl = document.getElementById('taskList');
    const btnStartWorkday = document.getElementById('btnStartWorkday');
    const btnEndWorkday = document.getElementById('btnEndWorkday');
    const workdayStartTimeEl = document.getElementById('workdayStartTime');
    const workdayDurationEl = document.getElementById('workdayDuration');
    const productivityRateEl = document.getElementById('productivityRate');
    const totalPointsCompletedEl = document.getElementById('totalPointsCompleted');
    const currentTaskNameEl = document.getElementById('currentTaskName');
    const currentTaskTimerEl = document.getElementById('currentTaskTimer');
    const btnPauseResumeTask = document.getElementById('btnPauseResumeTask');
    const btnStopTask = document.getElementById('btnStopTask');

    // --- ESTADO DA APLICAÇÃO ---
    let state = {
        tasks: [],
        workday: { startTime: null, endTime: null, durationTimer: null, totalSeconds: 0, totalEffectiveSeconds: 0 },
        currentTask: { id: null, timer: null, isPaused: false, effectiveSeconds: 0 },
    };

    // --- FUNÇÕES DE UTILIDADE ---
    const formatTime = (totalSeconds) => {
        if (isNaN(totalSeconds) || totalSeconds < 0) return "00:00:00";
        const hours = Math.floor(totalSeconds / 3600);
        const minutes = Math.floor((totalSeconds % 3600) / 60);
        const seconds = Math.floor(totalSeconds % 60);
        return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    };

    const formatTimeHours = (totalSeconds) => {
        if (isNaN(totalSeconds) || totalSeconds <= 0) return 0;
        return totalSeconds / 3600;
    };

    // --- RENDERIZAÇÃO E UI ---
    const renderTasks = () => {
        if (!taskListEl) return;
        if (state.tasks.length === 0) {
            taskListEl.innerHTML = '<p class="text-gray-500 text-center py-4">Nenhuma tarefa adicionada ainda.</p>';
            return;
        }
        taskListEl.innerHTML = '';
        state.tasks.forEach(task => {
            const taskEl = document.createElement('div');
            taskEl.className = `p-4 border rounded-lg flex items-center justify-between transition-all duration-300 ${task.status === 'completed' ? 'bg-green-50 border-green-200' : 'bg-white'} ${state.currentTask.id === task.id ? 'task-active' : ''}`;
            taskEl.id = `task-${task.id}`;
            let statusIndicator = '';
            if (task.status === 'completed') {
                statusIndicator = '<span class="text-xs font-medium bg-green-100 text-green-800 py-1 px-2 rounded-full">Concluída</span>';
            } else if (task.status === 'in-progress') {
                statusIndicator = '<span class="text-xs font-medium bg-blue-100 text-blue-800 py-1 px-2 rounded-full">Em Progresso</span>';
            }
            taskEl.innerHTML = `
                <div>
                    <p class="font-semibold">${task.name} <span class="text-sm font-normal text-gray-500">(${task.code || 'N/C'})</span></p>
                    <p class="text-sm text-gray-600">Pontos: ${task.points} | Duração Efetiva: ${formatTime(task.effectiveDuration)}</p>
                </div>
                <div class="flex items-center space-x-2">
                    ${statusIndicator}
                    <button data-task-id="${task.id}" class="btn-start-task bg-blue-500 hover:bg-blue-600 text-white p-2 rounded-full disabled:bg-gray-300 disabled:cursor-not-allowed" ${task.status !== 'pending' || !state.workday.startTime || !!state.currentTask.id ? 'disabled' : ''} title="Iniciar Tarefa">
                        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
                    </button>
                </div>
            `;
            taskListEl.appendChild(taskEl);
        });
        document.querySelectorAll('.btn-start-task').forEach(btn => {
            btn.addEventListener('click', () => handleStartTask(btn.dataset.taskId));
        });
    };

    const updateUI = () => {
        renderTasks();
        btnStartWorkday.disabled = !!state.workday.startTime;
        btnEndWorkday.disabled = !state.workday.startTime || !!state.workday.endTime || !!state.currentTask.id;
        
        const hasActiveTask = !!state.currentTask.id;
        btnPauseResumeTask.disabled = !hasActiveTask;
        btnStopTask.disabled = !hasActiveTask;
        btnPauseResumeTask.textContent = state.currentTask.isPaused ? 'Retomar' : 'Pausar';
        btnPauseResumeTask.className = `btn font-bold py-2 px-4 rounded-lg ${state.currentTask.isPaused ? 'bg-green-500 hover:bg-green-600' : 'bg-yellow-500 hover:bg-yellow-600'} text-white`;

        const totalCompletedPoints = state.tasks.filter(t => t.status === 'completed').reduce((sum, t) => sum + parseInt(t.points, 10), 0);
        totalPointsCompletedEl.textContent = totalCompletedPoints;
        const hoursWorked = formatTimeHours(state.workday.totalEffectiveSeconds);
        const productivity = hoursWorked > 0 ? (totalCompletedPoints / hoursWorked).toFixed(2) : '0.00';
        productivityRateEl.textContent = productivity;
    };

    // --- LÓGICA DE NEGÓCIO ---
    function handleStartWorkday() {
        state.workday.startTime = new Date();
        workdayStartTimeEl.textContent = state.workday.startTime.toLocaleTimeString();
        state.workday.durationTimer = setInterval(() => {
            state.workday.totalSeconds = Math.floor((new Date() - state.workday.startTime) / 1000);
            workdayDurationEl.textContent = formatTime(state.workday.totalSeconds);
            if (state.currentTask.id && !state.currentTask.isPaused) {
                state.workday.totalEffectiveSeconds++;
                updateUI();
            }
        }, 1000);
        updateUI();
    }
    
    function handleEndWorkday() {
        // Lógica para finalizar a jornada
        if(state.currentTask.id) {
            alert('Por favor, finalize a tarefa atual antes de encerrar a jornada.');
            return;
        }
        clearInterval(state.workday.durationTimer);
        state.workday.endTime = new Date();
        updateUI();
        // Aqui você chamaria google.script.run para salvar os dados da jornada, se necessário
    }

    function handleAddTask(e) {
        e.preventDefault();
        const form = e.target;
        const newTask = {
            name: form.taskName.value,
            code: form.taskCode.value,
            points: parseInt(form.taskPoints.value, 10),
            status: 'pending',
            effectiveDuration: 0
        };
        form.querySelector('button[type="submit"]').disabled = true;
        google.script.run
            .withSuccessHandler(taskAdicionadaComSucesso)
            .withFailureHandler(falhaAoSalvar)
            .addTask(newTask);
    }

    function taskAdicionadaComSucesso(taskComId) {
        formAddTask.reset();
        formAddTask.querySelector('button[type="submit"]').disabled = false;
        state.tasks.push(taskComId);
        updateUI();
    }

    function falhaAoSalvar(error) {
        alert('Erro ao salvar a tarefa: ' + error.message);
        formAddTask.querySelector('button[type="submit"]').disabled = false;
    }

    function handleStartTask(taskId) {
        if (state.currentTask.id) {
            alert('Já existe uma tarefa em andamento.');
            return;
        }
        const task = state.tasks.find(t => t.id === taskId);
        if (task) {
            task.status = 'in-progress';
            state.currentTask = { id: taskId, timer: null, isPaused: false, effectiveSeconds: parseInt(task.effectiveDuration, 10) || 0 };
            currentTaskNameEl.textContent = task.name;
            currentTaskTimerEl.textContent = formatTime(state.currentTask.effectiveSeconds);
            state.currentTask.timer = setInterval(() => {
                if (!state.currentTask.isPaused) {
                    state.currentTask.effectiveSeconds++;
                    currentTaskTimerEl.textContent = formatTime(state.currentTask.effectiveSeconds);
                }
            }, 1000);
            updateUI();
        }
    }

    function handlePauseResumeTask() {
        state.currentTask.isPaused = !state.currentTask.isPaused;
        updateUI();
    }

    function handleStopTask() {
        clearInterval(state.currentTask.timer);
        const taskId = state.currentTask.id;
        const task = state.tasks.find(t => t.id === taskId);
        if (task) {
            task.status = 'completed';
            task.effectiveDuration = state.currentTask.effectiveSeconds;
            google.script.run
                .withSuccessHandler(() => console.log(`Tarefa ${taskId} atualizada para 'completed' na planilha.`))
                .withFailureHandler((err) => alert(`Erro ao atualizar tarefa: ${err.message}`))
                .updateTaskStatus(taskId, 'completed', task.effectiveDuration);
        }
        state.currentTask = { id: null, timer: null, isPaused: false, effectiveSeconds: 0 };
        currentTaskNameEl.textContent = 'Nenhuma tarefa iniciada';
        currentTaskTimerEl.textContent = '00:00:00';
        updateUI();
    }

    // --- INICIALIZAÇÃO DA APLICAÇÃO ---
    function init() {
        // CORREÇÃO: Adicionando os listeners que estavam faltando
        formAddTask.addEventListener('submit', handleAddTask);
        btnStartWorkday.addEventListener('click', handleStartWorkday);
        btnEndWorkday.addEventListener('click', handleEndWorkday);
        btnPauseResumeTask.addEventListener('click', handlePauseResumeTask);
        btnStopTask.addEventListener('click', handleStopTask);

        // Busca os dados iniciais da planilha
        google.script.run
            .withSuccessHandler(dadosCarregadosComSucesso)
            .withFailureHandler(falhaAoCarregar)
            .getInitialData();
    }

    function dadosCarregadosComSucesso(data) {
        console.log("Dados recebidos da planilha:", data);
        state.tasks = data.tasks || [];
        loader.style.display = 'none';
        dashboardContent.classList.remove('hidden');
        updateUI();
    }

    function falhaAoCarregar(error) {
        loader.style.display = 'none';
        alert('Não foi possível carregar os dados da planilha: ' + error.message);
    }

    init();
});

Próximos Passos

  1. Substitua o código: Vá ao editor do Apps Script e substitua todo o conteúdo do seu dashboard.js pelo código corrigido acima.
  2. Salve o Projeto: Clique no ícone de disquete ("Salvar projeto").
  3. Teste Novamente: Acesse a URL da sua implantação do App da Web e execute o Caso de Teste 1 novamente.

Agora, os botões de jornada e de tarefas devem funcionar conforme o esperado. Por favor, realize os testes e me informe o resultado!

Pergunta ao Gemini

Olá, Gemini! O que fazer para salvar a mudança no Apps Script?

Resposta do Gemini

Olá! Ótima pergunta. Essa é uma etapa crucial e um ponto que confunde muitos iniciantes no Apps Script.

Salvar as alterações no Apps Script envolve duas fases: 1) Salvar o código no editor e 2) Publicar as alterações para que elas apareçam no seu aplicativo web.

Aqui está o passo a passo detalhado:

Fase 1: Salvar o Código no Editor

Esta é a parte mais simples. Você tem duas maneiras principais de fazer isso:

  1. Usando o Ícone de Salvar:

    • No topo do editor do Apps Script, procure pelo ícone de um disquete 💾.
    • Clique neste ícone (Salvar projeto) para salvar todas as alterações que você fez nos seus arquivos (Code.gs, Dashboard.html, etc.).
  2. Usando o Atalho de Teclado:

    • Como na maioria dos editores, você pode usar o atalho de teclado:
      • Ctrl + S (no Windows ou Linux)
      • Cmd + S (no Mac)

Dica: Você saberá que um arquivo tem alterações não salvas se aparecer um pequeno asterisco * ao lado do nome do arquivo na aba. Depois de salvar, o asterisco desaparece.


Fase 2: Publicar (Implantar) as Alterações no Aplicativo Web

Esta é a parte mais importante e que muitas vezes é esquecida. Apenas salvar o código não atualiza a URL do seu aplicativo web. Você precisa criar uma nova versão da sua implantação.

  1. Abra o Gerenciador de Implantações:

    • No topo da tela, clique no botão azul Implantar.
    • No menu que aparecer, selecione Gerenciar implantações.
  2. Edite sua Implantação Ativa:

    • Você verá sua implantação do "App da Web" na lista. Ela estará marcada como "Ativa".
    • À direita dela, clique no ícone de lápis (✏️) para editar.
  3. Crie uma Nova Versão:

    • Na caixa de diálogo que se abre, o mais importante é o seletor Versão.
    • Clique nele e escolha Nova versão.
  4. Implante a Nova Versão:

    • Clique no botão azul Implantar na parte inferior da caixa.

Pronto! Suas alterações agora estão ativas na URL do seu aplicativo web. Você pode recarregar a página do seu dashboard para ver os bugs corrigidos.

Resumo Rápido

Salvar (💾) + Implantar (⚙️ Nova versão) = Mudanças no ar!

Sempre que fizer uma alteração no código que queira ver refletida no seu site, você precisa seguir esses dois passos.


CONCLUSÃO

Após instalar a correção, o Caso de Teste 1 será executado outra vez.

Resultado do Caso de Teste 1, após corrigir o BugCT1-8: falhou.

No próximo post será apresentado o resultado do teste da correção do BugCT1-8.

Entendendo a Metáfora "Home Office é Moto Boy"

Exemplos D2P T2E2: Exemplo de uso do app D2P - Lição 1

INTRODUÇÃO Post anterior:  Exemplos D2P T2E1: Exemplo de uso do app D2P - Introdução Este é o episódio 2 da temporada 1 da série  Exemplos D...