Skip to content

Commit

Permalink
fix: replace regex and add test coverage (#225)
Browse files Browse the repository at this point in the history
Fixes regression from #220
Closes #224
  • Loading branch information
jukben authored Oct 13, 2021
1 parent 182ed80 commit 79c767d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 26 deletions.
36 changes: 15 additions & 21 deletions cypress/integration/textarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ describe("React Textarea Autocomplete", () => {
.should("have.value", "This is test🙄");
});

it("should respect already written tokens", () => {
cy.get(".rta__textarea")
.type("This is test -f{enter} and -s{downarrow}{enter}")
.should("have.value", "This is test -first and -second");
});

it("special character like [, ( should be also possible to use as trigger char", () => {
cy.get(".rta__textarea")
.type("This is test [{enter}")
Expand Down Expand Up @@ -99,7 +105,7 @@ describe("React Textarea Autocomplete", () => {
.then(() => {
const endLeft = Cypress.$(".rta__autocomplete").css("left");
cy.get(".rta__autocomplete").should("to.have.css", {
left: startLeft
left: startLeft,
});

expect(startLeft).to.be.equal(endLeft);
Expand Down Expand Up @@ -136,10 +142,10 @@ describe("React Textarea Autocomplete", () => {

it("onItemHighlighted should return correct item and trigger", () => {
cy.get(".rta__textarea").type(":ro{uparrow}{uparrow}");
cy.window().then(async win => {
cy.window().then(async (win) => {
const shouldSelectItem = {
currentTrigger: ":",
item: { name: "rofl", char: "🤣" }
item: { name: "rofl", char: "🤣" },
};

expect(win.__lastHighlightedItem).to.deep.equal(shouldSelectItem);
Expand All @@ -148,21 +154,17 @@ describe("React Textarea Autocomplete", () => {

it("onItemSelected should return correct item and trigger", () => {
cy.get(".rta__textarea").type(":ro{uparrow}{uparrow}{enter}");
cy.window().then(async win => {
cy.window().then(async (win) => {
const shouldSelectItem = {
currentTrigger: ":",
item: { name: "rofl", char: "🤣" }
item: { name: "rofl", char: "🤣" },
};

expect(win.__lastSelectedItem).to.deep.equal(shouldSelectItem);
});
});

it("should have place caret before outputted word", () => {
/**
* This is probably Cypress bug (1.0.2)
* This test needs to be run in headed mode, otherwise fails
*/
cy.get('[data-test="caretStart"]').click();

cy.get(".rta__textarea").type("This is test :ro{downarrow}{downarrow}");
Expand All @@ -173,10 +175,6 @@ describe("React Textarea Autocomplete", () => {
});

it("should place caret after word", () => {
/**
* This is probably Cypress bug (1.0.2)
* This test needs to be run in headed mode, otherwise fails
*/
cy.get('[data-test="caretEnd"]').click();

cy.get(".rta__textarea").type("This is test :ro{downarrow}{downarrow}");
Expand All @@ -187,10 +185,6 @@ describe("React Textarea Autocomplete", () => {
});

it("should caret after word with a space", () => {
/**
* This is probably Cypress bug (1.0.2)
* This test needs to be run in headed mode, otherwise fails
*/
cy.get('[data-test="caretNext"]').click();

cy.get(".rta__textarea").type("This is test :ro{downarrow}{downarrow}");
Expand Down Expand Up @@ -266,7 +260,7 @@ describe("React Textarea Autocomplete", () => {
cy.get(".rta__textarea").type(
`${repeat("{backspace}", 13)} again {downarrow}{enter}`,
{
force: true
force: true,
}
);
cy.get(".rta__textarea").should("have.value", "This is test /");
Expand Down Expand Up @@ -366,7 +360,7 @@ describe("React Textarea Autocomplete", () => {
.get("li:nth-child(1)")
.click();
cy.get(".rta__textarea").type(`${repeat("\n", 5)} test :a`, {
force: true
force: true,
});
cy.get(".rta__autocomplete").should(
"have.class",
Expand Down Expand Up @@ -395,13 +389,13 @@ describe("React Textarea Autocomplete", () => {
});

it("event is successfully blocked", () => {
cy.window().then(async win => {
cy.window().then(async (win) => {
const spy = cy.spy(win.console, "log");

await cy
.get(".rta__textarea")
.type(":ro{uparrow}{uparrow}{enter}")
.then(e => {
.then((e) => {
// the last console.log call should not be `pressed "enter"` because that event is blocked because it's happening in autocomplete.
expect(spy.lastCall.args).to.eql([`pressed "o"`]);
});
Expand Down
12 changes: 11 additions & 1 deletion example/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,17 @@ class App extends React.Component {
text: `${trigger}${item.name}`,
caretPosition: "end"
})
}
},
"-": {
dataProvider: token => {
return [
{ name: "f", char: "-first" },
{ name: "s", char: "-second" }
];
},
component: Item,
output: this._outputCaretEnd
},
}}
/>
{!showSecondTextarea ? null : (
Expand Down
9 changes: 5 additions & 4 deletions src/Textarea.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ class ReactTextareaAutocomplete extends React.Component<

_onSelect = (item: Object | string) => {
const { selectionEnd, currentTrigger, value: textareaValue } = this.state;
const { trigger, onItemSelected } = this.props;
const { onItemSelected } = this.props;

if (!currentTrigger) return;

Expand Down Expand Up @@ -437,14 +437,15 @@ class ReactTextareaAutocomplete extends React.Component<

/**
* It's important to escape the currentTrigger char for chars like [, (,...
* This is a ridiculous dark magic, basically we found position of the last current token (from current trigger) and then we replace the text from that position (calculating the offset)
*/
const escapedCurrentTrigger = escapeRegex(currentTrigger);
const escapedCurrentTriggerWithWhitespace = escapedCurrentTrigger + (trigger[currentTrigger].allowWhitespace ? "" : "\\s");
const triggerOffset = textToModify.length - textToModify.lastIndexOf(currentTrigger);
const startOfTokenPosition = textToModify.search(
new RegExp(
`${escapedCurrentTrigger}((?!${escapedCurrentTriggerWithWhitespace}).)*$`
`(?!${escapedCurrentTrigger})$`
)
);
) - triggerOffset;

// we add space after emoji is selected if a caret position is next
const newTokenString =
Expand Down

0 comments on commit 79c767d

Please sign in to comment.