Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui5-expandable-text): add ExpandableText component #10220

Merged
merged 33 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1296788
feat(ui5-expandable-text): add ExpandableText component
dimovpetar Nov 20, 2024
e1efcec
test: add first test
dimovpetar Nov 20, 2024
d635a18
test: add more tests
dimovpetar Nov 20, 2024
b1ffd45
test: add tests for popover
dimovpetar Nov 21, 2024
302ddf4
test: simplify them using aliases
dimovpetar Nov 21, 2024
3a13eb7
test: add tests for empty text and 0 max characters
dimovpetar Nov 21, 2024
4aae06c
feat: implement emtpyIndicatorMode
dimovpetar Nov 21, 2024
aae938e
feat: take Show More and Show Less from messagebundle
dimovpetar Nov 21, 2024
b17b561
feat: add mobile support
dimovpetar Nov 22, 2024
6995c88
fix: closing popover on toggle click now works
dimovpetar Nov 22, 2024
0ff19cb
test: add kh handling tests
dimovpetar Nov 22, 2024
c15972e
Merge branch 'main' of github.com:SAP/ui5-webcomponents into feat_exp…
dimovpetar Nov 22, 2024
6a69688
docs: add basic sample
dimovpetar Nov 22, 2024
b0a9117
docs: fix closing tag issue
dimovpetar Dec 2, 2024
e2f1355
Merge branch 'main' of github.com:SAP/ui5-webcomponents into feat_exp…
dimovpetar Dec 2, 2024
3bc1f3b
feat: add SR support
dimovpetar Dec 2, 2024
915a1fa
fix: apply proper popover paddings
dimovpetar Dec 2, 2024
a17e608
refactor: import i18n texts in tests
dimovpetar Dec 2, 2024
3d10731
refactor: tests
dimovpetar Dec 2, 2024
1ebb1df
docs: add samples
dimovpetar Dec 2, 2024
8a0374a
test: add rtl test sample
dimovpetar Dec 2, 2024
a8874fe
chore: update popover workaround
dimovpetar Dec 3, 2024
452187f
feat: change maxCharacters default value to 100
dimovpetar Dec 3, 2024
c47e273
Merge branch 'main' of github.com:SAP/ui5-webcomponents into feat_exp…
dimovpetar Dec 3, 2024
e8f0d32
fix: add workaround for Show Less opening the popover
dimovpetar Dec 3, 2024
c00b2da
test: use text from i18n bundle
dimovpetar Dec 3, 2024
a49c056
Merge branch 'main' of github.com:SAP/ui5-webcomponents into feat_exp…
dimovpetar Dec 4, 2024
4888695
docs: update
dimovpetar Dec 5, 2024
72b6db7
docs: use tables in samples
dimovpetar Dec 5, 2024
e932222
fix: set accessible-name-ref of the popover
dimovpetar Dec 6, 2024
3fa4184
docs: increase samples height
dimovpetar Dec 6, 2024
dc7ed48
docs: fix module path in JSdoc
dimovpetar Dec 6, 2024
e00ab1b
docs: reword some sentences
dimovpetar Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
387 changes: 387 additions & 0 deletions packages/main/cypress/specs/ExpandableText.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
import { html } from "lit";
import "../../src/ExpandableText.js";
import {
EXPANDABLE_TEXT_SHOW_MORE,
EXPANDABLE_TEXT_SHOW_LESS,
EXPANDABLE_TEXT_CLOSE,
} from "../../src/generated/i18n/i18n-defaults.js";

describe("ExpandableText", () => {
describe("Rendering and Interaction", () => {
it("Should display only 100 characters by default", () => {
const text = "This is a very long text that should be displayed. This is a very long text that should be displayed. This is a very long text that should be displayed.";

cy.mount(html`<ui5-expandable-text text=${text}></ui5-expandable-text>`);

expect(text.length).to.be.greaterThan(100);

cy.get("[ui5-expandable-text]")
.shadow()
.find("[ui5-text]")
.contains(text.substring(0, 100))
.should("exist");
});

it("Should display full text if maxCharacters are set, but not exceeded", () => {
const text = "This is a very long text that should be displayed";

cy.mount(html`<ui5-expandable-text text=${text} max-characters="9999"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]")
.shadow()
.find("[ui5-text]")
.contains(text)
.should("exist");
});

it("Should display 'Show More' if maxCharacters are set and exceeded", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`<ui5-expandable-text text=${text} max-characters="${maxCharacters}"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text.substring(0, maxCharacters))
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-ellipsis")
.contains("... ")
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.should("exist")
.should("have.attr", "ui5-link");
});

it("Should display 'Show More' if maxCharacters are exceeded, set to 0", () => {
const text = "This is a very long text that should be displayed";

cy.mount(html`<ui5-expandable-text text=${text} max-characters="0"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(/^$/)
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-ellipsis")
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.should("exist");
});

it("Should NOT display 'Show More' if maxCharacters are 0, but text is empty", () => {
cy.mount(html`<ui5-expandable-text max-characters="0"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(/^$/)
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-ellipsis")
.should("not.exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-toggle")
.should("not.exist");
});

it("Toggling 'Show More' and 'Show Less'", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`<ui5-expandable-text text=${text} max-characters="${maxCharacters}"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.realClick();

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text)
.should("exist");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_LESS.defaultText)
.realClick();

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text.substring(0, maxCharacters))
.should("exist");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.should("exist");
});

it("Toggling 'Show More' and 'Show Less' with keyboard", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`
<button id="before">before</button>
<ui5-expandable-text text=${text} max-characters="${maxCharacters}"></ui5-expandable-text>
`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("#before")
.focus();

cy.get("#before")
.realPress("Tab");

cy.get("@toggle")
.realPress("Enter");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text)
.should("exist");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_LESS.defaultText)
.realPress("Enter");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text.substring(0, maxCharacters))
.should("exist");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.should("exist");
});

it("ARIA attributes", () => {
const text = "This is a very long text that should be displayed";

cy.mount(html`<ui5-expandable-text text=${text} max-characters="5"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find("[ui5-text]").as("text");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("@toggle")
.should("have.attr", "accessible-role", "Button");

cy.get("@toggle")
.invoke("prop", "accessibilityAttributes")
.should("deep.equal", {
expanded: false,
});

cy.get("@toggle")
.realClick();

cy.get("@toggle")
.invoke("prop", "accessibilityAttributes")
.should("deep.equal", {
expanded: true,
});
});
});

describe("Empty Indicator", () => {
it("Should display empty indicator if text is empty and emptyIndicatorMode=On", () => {
cy.mount(html`<ui5-expandable-text text="" empty-indicator-mode="On"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]")
.shadow()
.find("[ui5-text]")
.should("have.attr", "empty-indicator-mode", "On");
});

it("Should NOT display empty indicator if text is empty and emptyIndicatorMode=Off", () => {
cy.mount(html`<ui5-expandable-text text="" empty-indicator-mode="Off"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]")
.shadow()
.find("[ui5-text]")
.should("have.attr", "empty-indicator-mode", "Off");
});
});

describe("Rendering and Interaction with overflowMode=Popover", () => {
it("Toggling 'Show More' and 'Show Less'", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`<ui5-expandable-text text=${text} max-characters="${maxCharacters}" overflow-mode="Popover"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("@expTextShadow")
.find("[ui5-text]")
.contains(text.substring(0, maxCharacters))
.should("exist");

cy.get("@expTextShadow")
.find(".ui5-exp-text-ellipsis")
.contains("... ")
.should("exist");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.realClick();

cy.get("@toggle")
.invoke("attr", "id")
.as("expectedOpenerId");

cy.get("@expTextShadow")
.find("[ui5-responsive-popover]")
.as("rpo");

cy.get("@rpo")
.should("exist")
.should("have.attr", "open");

cy.get("@rpo")
.should("have.attr", "content-only-on-desktop");

cy.get("@rpo")
.invoke("attr", "opener")
.then(function testOpenerId(opener) {
expect(opener).to.equal(this.expectedOpenerId);
});

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_LESS.defaultText)
.realClick();

cy.get("@expTextShadow")
.find("[ui5-responsive-popover]")
.should("not.have.attr", "open");
});

it("ARIA attributes", () => {
const text = "This is a very long text that should be displayed";

cy.mount(html`<ui5-expandable-text text=${text} max-characters="5" overflow-mode="Popover"></ui5-expandable-text>`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find("[ui5-text]").as("text");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("@toggle")
.should("have.attr", "accessible-name");

cy.get("@toggle")
.invoke("prop", "accessibilityAttributes")
.should("deep.equal", {
expanded: false,
hasPopup: "dialog",
});

cy.get("@toggle")
.realClick();

cy.get("@toggle")
.invoke("prop", "accessibilityAttributes")
.should("deep.equal", {
expanded: true,
hasPopup: "dialog",
});
});

it("Toggling 'Show More' and 'Show Less' with keyboard", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`
<button id="before">before</button>
<ui5-expandable-text text=${text} max-characters="${maxCharacters}" overflow-mode="Popover"></ui5-expandable-text>
`);

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");
cy.get("@expTextShadow").find(".ui5-exp-text-toggle").as("toggle");

cy.get("#before")
.focus();

cy.get("#before")
.realPress("Tab");

cy.get("@toggle")
.realPress("Enter");

cy.get("@expTextShadow")
.find("[ui5-responsive-popover]")
.as("rpo");

cy.get("@rpo")
.should("exist")
.should("have.attr", "open");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_LESS.defaultText)
.should("exist");

cy.realPress("Escape");

cy.get("@rpo")
.should("not.have.attr", "open");

cy.get("@toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.should("exist");
});

it("Toggling 'Show More' and 'Show Less' on Mobile Device", () => {
const text = "This is a very long text that should be displayed";
const maxCharacters = 5;

cy.mount(html`<ui5-expandable-text text=${text} max-characters="${maxCharacters}" overflow-mode="Popover"></ui5-expandable-text>`);
cy.ui5SimulateDevice("phone");

cy.get("[ui5-expandable-text]").shadow().as("expTextShadow");

cy.get("@expTextShadow")
.find(".ui5-exp-text-toggle")
.contains(EXPANDABLE_TEXT_SHOW_MORE.defaultText)
.realClick();

cy.get("@expTextShadow")
.find("[ui5-responsive-popover]").as("rpo");

cy.get("@rpo")
.should("exist")
.should("have.attr", "open");

cy.get("@rpo")
.should("have.attr", "_hide-header");

cy.get("@rpo")
.contains("[slot=footer] [ui5-button]", EXPANDABLE_TEXT_CLOSE.defaultText)
.should("exist");

cy.get("@rpo")
.contains("[slot=footer] [ui5-button]", EXPANDABLE_TEXT_CLOSE.defaultText)
.realClick();

cy.get("@rpo")
.should("not.have.attr", "open");
});
});
});
Loading
Loading