[IMP] web, *: add tests to TagsList component

*: project

This commit adds test to this component and removes unused props. Since commit (1),
it is now considered as a core component. Those props have been removed from the
props declaration, to better match the real usage of the component.

Since the className props was not present:
- The o_kanban_tag class given in theory were not set in practice. The rules
corresponding to that class were already adapted to fix the display of tags in the
kanban view. It was possible to get rid of the references to the o_kanban_tag class.

- The o_field_property_tag_readonly class was also missing, and the logic to prevent
the click on tags was duplicated in the onTagClick function. This makes the class
useless. I removed mentions to this classname. Instead, each tag has the pe-none class
using the same condition, but set in the tag declaration.

(1): 129fa3f150

Part-of: odoo/odoo#117751
This commit is contained in:
luvi
2023-04-06 12:48:31 +02:00
parent 0e2c84592f
commit 0b2b151784
9 changed files with 162 additions and 17 deletions
@@ -37,7 +37,7 @@
cursor: pointer;
}
.o_kanban_project_tasks .o_kanban_renderer .o_field_many2manytags, .o_kanban_tags{
.o_kanban_project_tasks .o_kanban_renderer .o_field_many2manytags{
margin: 0px;
}
@@ -5,17 +5,14 @@ import { Component } from "@odoo/owl";
export class TagsList extends Component {
static template = "web.TagsList";
static defaultProps = {
className: "",
displayBadge: true,
displayText: true,
};
static props = {
className: { type: String, optional: true },
displayBadge: { type: Boolean, optional: true },
displayText: { type: Boolean, optional: true },
name: { type: String, optional: true },
itemsVisible: { type: Number, optional: true },
tags: { type: Object, optional: true },
tags: { type: Object },
};
get visibleTagsCount() {
return this.props.itemsVisible - 1;
@@ -3,7 +3,7 @@
<t t-name="web.TagsList" owl="1">
<t t-foreach="visibleTags" t-as="tag" t-key="tag.id or tag_index">
<span t-attf-class="{{`o_tag_color_${ tag.colorIndex or 0 } ${props.displayBadge ? 'badge rounded-pill' : ''}`}} o_tag d-inline-flex align-items-center" t-att-class="tag.className" tabindex="-1" t-att-data-color="tag.colorIndex" t-att-title="tag.text" t-on-click="(ev) => tag.onClick and tag.onClick(ev)" t-on-keydown="tag.onKeydown">
<span t-attf-class="{{`o_tag_color_${ tag.colorIndex or 0 } ${props.displayBadge ? 'badge rounded-pill' : ''}`}} o_tag d-inline-flex align-items-center" t-att-class="tag.className" tabindex="-1" t-att-data-color="tag.colorIndex" t-att-title="tag.text" t-on-click="(ev) => tag.onClick and tag.onClick(ev)" t-on-keydown="tag.onKeydown">
<img t-if="tag.img" t-att-src="tag.img" class="o_m2m_avatar rounded-circle"/>
<div t-if="props.displayBadge and props.displayText" class="o_tag_badge_text px-1" t-esc="tag.text" />
<t t-elif="props.displayText">
@@ -2,6 +2,6 @@
<templates xml:space="preserve">
<t t-name="web.KanbanMany2ManyTagsField" owl="1">
<TagsList className="'o_kanban_tags'" tags="tags" displayBadge="false" />
<TagsList tags="tags" displayBadge="false" />
</t>
</templates>
@@ -68,6 +68,7 @@ export class PropertyTags extends Component {
return {
id: tagId,
text: tagLabel,
className: this.props.canChangeTags ? "" : "pe-none",
colorIndex: tagColorIndex || 0,
onClick: (event) => this.onTagClick(event, tagId, tagColorIndex),
onDelete: canDeleteTag && (() => this.onTagDelete(tagId)),
@@ -1,9 +1,3 @@
.o_field_property_tag_readonly {
// deactivate all click interactions with tags
// if we can't change their definition
pointer-events: none;
}
.o_field_property_tag {
.o_tag {
margin: 1px 2px 1px 0;
@@ -5,8 +5,7 @@
<div t-attf-class="o_field_property_tag o_field_widget o_field_many2many_tags d-flex align-items-center {{props.readonly ? 'readonly' : ''}}">
<TagsList
tags="tagListItems"
displayBadge="displayBadge"
className="props.canChangeTags ? '' : 'o_field_property_tag_readonly' "/>
displayBadge="displayBadge"/>
<div
t-if="!props.readonly"
class="o_field_property_dropdown_menu o_input_dropdown mt-2">
@@ -281,8 +281,7 @@
}
// Kanban Record - Inner elements
.o_field_many2many_tags,
.o_kanban_tags {
.o_field_many2many_tags {
display: block;
margin-bottom: var(--KanbanRecord-gap-v);
line-height: 1.2;
@@ -0,0 +1,155 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { TagsList } from "@web/core/tags_list/tags_list";
import { makeTestEnv } from "../helpers/mock_env";
import { getFixture, patchWithCleanup, mount, click } from "../helpers/utils";
import { Component, xml } from "@odoo/owl";
QUnit.module("Web Components", (hooks) => {
QUnit.module("TagsList");
let env;
let target;
hooks.beforeEach(async () => {
env = await makeTestEnv();
target = getFixture();
patchWithCleanup(browser, {
setTimeout: (fn) => Promise.resolve().then(fn),
});
});
QUnit.test("Can be rendered with different tags", async (assert) => {
class Parent extends Component {
setup() {
this.tags = [
{
id: "tag1",
text: "Earth",
},
{
colorIndex: 1,
id: "tag2",
text: "Wind",
onDelete: () => {
assert.step(`tag2 delete button has been clicked`);
},
},
{
colorIndex: 2,
id: "tag3",
text: "Fire",
onClick: () => {
assert.step(`tag3 has been clicked`);
},
onDelete: () => {
assert.step(`tag3 delete button has been clicked`);
},
},
];
}
}
Parent.components = { TagsList };
Parent.template = xml`
<TagsList tags="tags" />`;
await mount(Parent, target, { env });
assert.containsN(target, ".o_tag", 3);
await click(target.querySelector(".o_tag:nth-of-type(2) .o_delete"));
assert.verifySteps(["tag2 delete button has been clicked"]);
await click(target.querySelector(".o_tag:nth-of-type(3)"));
assert.verifySteps(["tag3 has been clicked"]);
});
QUnit.test("Tags can be displayed with an image", async (assert) => {
class Parent extends Component {
setup() {
this.tags = [
{
img: "fake/url",
id: "tag1",
text: "Earth",
},
{
img: "fake/url/2",
id: "tag2",
text: "Wind",
},
];
}
}
Parent.components = { TagsList };
Parent.template = xml`
<TagsList tags="tags" />`;
await mount(Parent, target, { env });
assert.containsN(target, ".o_tag", 2);
assert.strictEqual(
target.querySelector(".o_tag:nth-of-type(1) img").dataset.src,
"fake/url"
);
assert.strictEqual(
target.querySelector(".o_tag:nth-of-type(2) img").dataset.src,
"fake/url/2"
);
});
QUnit.test("Limiting the visible tags displays a counter", async (assert) => {
class Parent extends Component {
setup() {
this.tags = [
{
id: "tag1",
text: "Water",
onDelete: () => {},
},
{
id: "tag2",
text: "Grass",
},
{
id: "tag3",
text: "Fire",
},
{
id: "tag4",
text: "Earth",
},
{
id: "tag5",
text: "Wind",
},
{
id: "tag6",
text: "Dust",
},
];
}
}
Parent.components = { TagsList };
Parent.template = xml`
<TagsList tags="tags" itemsVisible="3" />`;
await mount(Parent, target, { env });
assert.containsN(target, ".o_tag", 2);
const counter = target.querySelector(".rounded-circle");
assert.strictEqual(counter.textContent, "+4", "the counter displays 4 more items");
assert.deepEqual(
JSON.parse(counter.dataset.tooltipInfo),
{
tags: [
{ text: "Fire", id: "tag3" },
{ text: "Earth", id: "tag4" },
{ text: "Wind", id: "tag5" },
{ text: "Dust", id: "tag6" },
],
},
"the counter has a tooltip displaying other items"
);
});
});