19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:12 +01:00
parent 79f83631d5
commit 73afc09215
6267 changed files with 1534193 additions and 1130106 deletions

View file

@ -0,0 +1,145 @@
import { expect, test } from "@odoo/hoot";
import { waitForNone } from "@odoo/hoot-dom";
import {
contains,
dataURItoBlob,
defineModels,
fields,
models,
onRpc,
} from "@web/../tests/web_test_helpers";
import {
defineWebsiteModels,
setupWebsiteBuilder,
} from "@website/../tests/builder/website_helpers";
class ProductProduct extends models.Model {
_name = "product.product";
id = fields.Integer();
name = fields.Char();
image_1920 = fields.Image();
_records = [
{ id: 13, name: "Variant 1", image_1920: "/9j/4AAQSkL6D8wwP//Z" },
{ id: 14, name: "Variant 2", image_1920: null },
];
}
class ProductRibbon extends models.Model {
_name = "product.ribbon";
}
defineWebsiteModels();
defineModels([ProductProduct, ProductRibbon]);
test("Product page options", async () => {
const { waitSidebarUpdated } = await setupWebsiteBuilder(`
<main>
<div class="o_wsale_product_page">
<section
id="product_detail"
class="oe_website_sale mt-1 mt-lg-2 mb-5 o_wsale_container_lg container-lg
o_wsale_product_page_opt_image_width_66_pc
o_wsale_product_page_opt_image_ratio_1_1
o_wsale_product_page_opt_image_ratio_mobile_auto
o_wsale_product_page_opt_image_radius_none
o_wsale_product_page_opt_separators"
>
<div id="product_detail_main" data-image_layout="carousel">
<div class="o_wsale_product_images" data-image-amount="2">
<div id="o-carousel-product">
<div class="carousel-item h-100 text-center active o_colored_level" style="min-height: 693px;">
<div name="o_img_with_max_suggested_width"
class="d-flex align-items-start justify-content-center h-100 oe_unmovable o_editable"
data-oe-xpath="/t[1]/div[2]/div[1]" data-oe-model="product.product" data-oe-id="13"
data-oe-field="image_1920" data-oe-type="image"
data-oe-expression="product_image.image_1920" contenteditable="false">
<img>
</div>
</div>
<div class="carousel-item h-100 text-center active o_colored_level" style="min-height: 693px;">
<div name="o_img_with_max_suggested_width"
class="d-flex align-items-start justify-content-center h-100 oe_unmovable o_editable"
data-oe-xpath="/t[1]/div[2]/div[1]" data-oe-model="product.product" data-oe-id="14"
data-oe-field="image_1920" data-oe-type="image"
data-oe-expression="product_image.image_1920" contenteditable="false">
<img>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</main>`);
onRpc("/website/theme_customize_data", () => expect.step("theme_customize_data"));
onRpc("/website/theme_customize_data_get", () => expect.step("theme_customize_data_get"));
onRpc("/shop/config/website", () => expect.step("config"));
onRpc("ir.ui.view", "save", () => {
expect.step("save");
return [];
});
onRpc("product.product", "write", () => {
expect.step("product_write");
return true;
});
const base64Image =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5" +
"AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYIIA";
onRpc("ir.attachment", "search_read", () => [
{
mimetype: "image/png",
image_src: "/web/image/hoot.png",
access_token: false,
public: true,
},
]);
onRpc("/html_editor/get_image_info", () => {
expect.step("get_image_info");
return {
attachment: { id: 1 },
original: { id: 1, image_src: "/web/image/hoot.png", mimetype: "image/png" },
};
});
onRpc("/web/image/hoot.png", () => {
// converted image won't be used if original is not larger
return dataURItoBlob(base64Image + "A".repeat(1000));
});
await contains(":iframe .o_wsale_product_page").click();
await contains("[data-action-id=productReplaceMainImage]").click();
await contains(".o_select_media_dialog .o_existing_attachment_cell button").click();
await expect.waitForSteps(["theme_customize_data_get", "get_image_info", "product_write"]);
await waitForNone(".o_select_media_dialog");
expect(":iframe #product_detail_main img[src^='data:image/webp;base64,']").toHaveCount(1);
expect(":iframe img").toHaveCount(2);
await contains("button#o_wsale_image_width").click();
// Avoid selecting the first option to prevent the image layout option from disappearing
await contains("[data-action-id=productPageImageWidth][data-action-value='50_pc']").click();
await waitSidebarUpdated();
await expect.waitForSteps(["config"]);
await contains("button#o_wsale_image_layout").click();
await contains("[data-action-id=productPageImageLayout]").click();
await waitSidebarUpdated();
await expect.waitForSteps([
// Activate the carousel view and change the shop config
"config",
// Save the pending image width class changes
"save",
// Save the image changes
"save",
// Reload the view
"theme_customize_data_get",
]);
// Make sure that clicking quickly on a builder button after an clicking on
// an action that reloads the editor does not produce a crash.
await contains("[data-action-id=websiteConfig].o_we_buy_now_btn").click();
await contains("button#o_wsale_image_layout").click();
await expect.waitForSteps(["theme_customize_data", "theme_customize_data_get"]);
});

View file

@ -0,0 +1,60 @@
import { expect, test } from "@odoo/hoot";
import { contains, defineModels, models, onRpc } from "@web/../tests/web_test_helpers";
import {
defineWebsiteModels,
setupWebsiteBuilder,
} from "@website/../tests/builder/website_helpers";
class productRibbon extends models.Model {
_name = "product.ribbon";
}
defineWebsiteModels();
defineModels([productRibbon]);
test("add a new ribbon", async () => {
onRpc("product.ribbon", "create", () => [1]);
onRpc("product.template", "write", () => ({}));
await setupWebsiteBuilder(
`<div id="o_wsale_container" data-ppg="20" data-ppr="4" data-default-sort="website_sequence asc">
<div id="products_grid">
<section id="o_wsale_products_grid" class="o_wsale_products_grid_table grid o_wsale_products_grid_table_md" style="--o-wsale-ppr: 4; --o-wsale-ppg: 20" data-name="Grid">
<div class="oe_product" style="--o-wsale-products-grid-product-col-height: 1;" data-name="Product">
<div class="o_wsale_product_grid_wrapper o_wsale_product_grid_wrapper_1_1">
<form class="oe_product_cart" data-publish="off">
<div class="oe_product_image">
<a class="oe_product_image_link d-block position-relative" contenteditable="false" href="/shop/event-registration-4">
<span class="oe_product_image_img_wrapper d-flex h-100 justify-content-center align-items-center position-absolute"><img src="/web/image/product.template/4/image_512/product?unique=5c2586b" class="img img-fluid h-100 w-100 position-absolute"></span>
<span class="o_ribbon o_not_editable d-none" style=""></span>
</a>
</div>
<span
data-ribbon-id=""
class="o_ribbons o_not_editable"
style=""
/>
<div class="o_wsale_product_information">
<div class="o_wsale_product_information_text">
<h6 class="o_wsale_products_item_title">
<a data-oe-model="product.template" data-oe-id="4" data-oe-field="name" data-oe-type="char" data-oe-expression="product.name">
Test product
</a>
</h6>
</div>
<div class="o_wsale_product_sub">
<div class="product_price">
<span class="oe_currency_value">1.00</span>
</div>
</div>
</div>
</form>
</div>
</div>
</section>
</div>
</div>`
);
await contains(":iframe .oe_product").click();
await contains("button[data-action-id='createRibbon']").click();
expect(":iframe .oe_product .o_ribbons").toHaveText("Ribbon Name");
});