Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las páginas personalizadas son aplicaciones Canvas insertadas dentro de una aplicación basada en modelos. Se representan en un iframe dentro del shell de la aplicación controlada por modelos. Para probarlas, es necesario navegar a la aplicación controlada por modelos, seleccionar la página personalizada del mapa del sitio y, a continuación, determinar el ámbito de todas las interacciones de control en el iframe interno.
Funcionamiento de las pruebas de páginas personalizadas en aplicaciones controladas por modelos
Cuando se carga una página personalizada, el shell de aplicación controlado por modelos permanece en el dominio Dynamics 365. El tiempo de ejecución del lienzo de página personalizado se carga dentro de:
iframe[name="fullscreen-app-host"]
Este es el mismo iframe que usan las aplicaciones canvas independientes. Una vez que tenga el localizador, se aplicarán todos los patrones de pruebas para aplicaciones de canvas.
Navegar a una página personalizada
- Inicie la aplicación controlada por modelos mediante
AppProvider. - Seleccione el elemento de página personalizado en el mapa del sitio.
- Espere a que el runtime del canvas se inicialice.
import { test, expect } from '@playwright/test';
import { AppProvider, AppType, AppLaunchMode } from 'power-platform-playwright-toolkit';
const MODEL_DRIVEN_APP_URL = process.env.MODEL_DRIVEN_APP_URL!;
const CUSTOM_PAGE_NAME = process.env.CUSTOM_PAGE_NAME ?? 'AccountsCustomPage';
test.beforeAll(async ({ browser }) => {
const context = await browser.newContext({ storageState: mdaStorageStatePath });
const page = await context.newPage();
const app = new AppProvider(page, context);
await app.launch({
app: 'My App',
type: AppType.ModelDriven,
mode: AppLaunchMode.Play,
skipMakerPortal: true,
directUrl: MODEL_DRIVEN_APP_URL,
});
// Navigate to the custom page via the sitemap
const sidebarItem = page
.locator(`[role="presentation"][title="${CUSTOM_PAGE_NAME}"]`)
.first();
await sidebarItem.waitFor({ state: 'visible', timeout: 30000 });
await sidebarItem.click();
await page.waitForTimeout(3000);
});
Interacción con controles de página personalizados
Después de navegar a la página personalizada, limite los localizadores al iframe del lienzo.
const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
// Wait for gallery to appear
await canvasFrame
.locator('[data-control-part="gallery-item"]')
.first()
.waitFor({ state: 'visible', timeout: 30000 });
Botones de clic en controles de página personalizados
Use el data-control-name atributo para dirigir controles de botón específicos dentro del iframe de lienzo y, a continuación, busque el elemento interno [role="button"] para desencadenar una acción de clic.
await canvasFrame.locator('[data-control-name="IconButton_Accept1"] [role="button"]').click();
await canvasFrame.locator('[data-control-name="IconButton_Edit1"] [role="button"]').click();
Rellenar campos de formulario en una página personalizada
Busque los campos de entrada por su aria-label atributo dentro del iframe de lienzo y use el fill método para escribir valores.
const accountNameInput = canvasFrame.locator('input[aria-label="Account Name"]');
await accountNameInput.fill('Contoso Ltd');
Filtrar una galería por título en una página personalizada
Para buscar un elemento específico en una galería, filtre la lista de elementos de la galería haciendo coincidir el contenido de texto de un control secundario, como Title1.
const galleryItem = canvasFrame
.locator('[role="listitem"][data-control-part="gallery-item"]')
.filter({
has: canvasFrame
.locator('[data-control-name="Title1"]')
.getByText('Contoso Ltd', { exact: true }),
});
await galleryItem.waitFor({ state: 'visible', timeout: 30000 });
Actualizar la página personalizada después de guardar
Al guardar un nuevo registro en una página personalizada respaldada por Dataverse, la galería no se actualiza automáticamente a menos que desencadene una recarga completa. El enfoque recomendado es ir a la raíz de la aplicación y volver a:
// Navigate to app root to force gallery refresh
await page.goto(MODEL_DRIVEN_APP_URL, { waitUntil: 'load', timeout: 60000 });
await page.locator('[role="menuitem"]').first().waitFor({ state: 'visible', timeout: 30000 });
// Navigate back to the custom page
const sidebarItem = page.locator(`[role="presentation"][title="${CUSTOM_PAGE_NAME}"]`).first();
await sidebarItem.waitFor({ state: 'visible', timeout: 30000 });
await sidebarItem.click();
// Wait for the new record to appear in the gallery
const specificItem = page
.locator('[data-control-part="gallery-item"]')
.filter({ has: page.locator('[data-control-name="Title1"]').getByText(accountName, { exact: true }) });
await specificItem.waitFor({ state: 'visible', timeout: 60000 });
Ejemplo de prueba completo: creación y comprobación de un registro
En el ejemplo siguiente se combina la navegación, la entrada de formulario, el guardado y la comprobación de la galería en una única prueba de un extremo a otro que crea un registro de cuenta y confirma que aparece en la galería de páginas personalizada.
test('should create an account and verify it in the gallery', async ({ page }) => {
const ACCOUNT_NAME = `Test Account ${Date.now()}`;
const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
// Click New record
await page.locator('[title="New record"]').click();
// Fill the form
await canvasFrame.locator('input[aria-label="Account Name"]').fill(ACCOUNT_NAME);
await canvasFrame.locator('input[aria-label="Main Phone"]').fill('555-1234');
// Save
await canvasFrame
.locator('[data-control-name="IconButton_Accept1"] [role="button"]')
.click();
// Refresh and verify
await page.waitForTimeout(5000); // wait for Dataverse write
await page.goto(MODEL_DRIVEN_APP_URL, { waitUntil: 'load', timeout: 60000 });
await page.locator('[role="menuitem"]').first().waitFor({ timeout: 30000 });
await page.locator(`[role="presentation"][title="${CUSTOM_PAGE_NAME}"]`).first().click();
await expect(
page
.locator('[data-control-part="gallery-item"]')
.filter({ has: page.locator('[data-control-name="Title1"]').getByText(ACCOUNT_NAME, { exact: true }) })
).toBeVisible({ timeout: 60000 });
});
Autenticación para páginas personalizadas
Las páginas personalizadas se ejecutan en el dominio de Dynamics 365. Use el estado de almacenamiento de aplicaciones controlado por modelos:
test.use({
storageState: path.join(
path.dirname(getStorageStatePath(process.env.MS_AUTH_EMAIL!)),
`state-mda-${process.env.MS_AUTH_EMAIL}.json`
),
});
Pasos siguientes
- Probar aplicaciones de generación de experiencia de usuario
- Modelo de objetos de página
- Pruebas de ejemplo