Skip to content

Commit

Permalink
Refine tests more.
Browse files Browse the repository at this point in the history
  • Loading branch information
mathewjordan committed Jan 28, 2025
1 parent 406815d commit c6fa6c0
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 87 deletions.
13 changes: 0 additions & 13 deletions components/Chat/Chat.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,6 @@ describe("Chat component", () => {
const dataProps = el.getAttribute("data-props");
const dataPropsObj = JSON.parse(dataProps!);
expect(dataPropsObj.question).toEqual("tell me about boats");
expect(dataPropsObj.isStreamingComplete).toEqual(false);
expect(dataPropsObj.message).toEqual({
answer: "fake-answer-1",
end: "stop",
});
expect(typeof dataPropsObj.conversationRef).toBe("string");
expect(uuidRegex.test(dataPropsObj.conversationRef)).toBe(true);
});
Expand All @@ -106,14 +101,6 @@ describe("Chat component", () => {
<Chat />
</SearchProvider>,
);

expect(mockMessage).toHaveBeenCalledWith(
expect.objectContaining({
auth: "fake-token",
message: "chat",
question: "boats",
}),
);
});

it("doesn't send a websocket message if the search term is empty", () => {
Expand Down
24 changes: 7 additions & 17 deletions components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import React, { useEffect, useState } from "react";

import { AI_SEARCH_UNSUBMITTED } from "@/lib/constants/common";
import ChatConversation from "./Conversation";
import ChatFeedback from "@/components/Chat/Feedback/Feedback";
import ChatResponse from "@/components/Chat/Response/Response";
import Container from "@/components/Shared/Container";
import { StyledUnsubmitted } from "./Response/Response.styled";
import { styled } from "@/stitches.config";
import useQueryParams from "@/hooks/useQueryParams";
import { v4 as uuidv4 } from "uuid";

Expand Down Expand Up @@ -59,7 +59,7 @@ const Chat = () => {

return (
<Container>
<section
<StyledChat
data-conversation-initial={searchTerm}
data-conversation-length={conversation.length}
data-conversation-ref={conversationRef}
Expand All @@ -80,23 +80,13 @@ const Chat = () => {
conversationCallback={handleConversationCallback}
isStreaming={isStreaming}
/>
{isStreaming && (
<>
{/* <StyledResponseActions>
<Button isPrimary isLowercase onClick={viewResultsCallback}>
View More Results
</Button>
<Button isLowercase onClick={handleNewQuestion}>
Ask Another Question
</Button>
</StyledResponseActions>
<StyledResponseDisclaimer>{AI_DISCLAIMER}</StyledResponseDisclaimer> */}
{/* <ChatFeedback /> */}
</>
)}
</section>
</StyledChat>
</Container>
);
};

const StyledChat = styled("section", {
padding: "$gr5 0",
});

export default Chat;
16 changes: 16 additions & 0 deletions components/Chat/Conversation.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { render, screen } from "@/test-utils";

import ChatConversation from "./Conversation";

describe("Conversaton component", () => {
const handleConversationCallback = jest.fn();

it("renders a chat conversation", () => {
render(
<ChatConversation conversationCallback={handleConversationCallback} />,
);

const wrapper = screen.getByTestId("chat-conversation");
expect(wrapper).toBeInTheDocument();
});
});
46 changes: 34 additions & 12 deletions components/Chat/Conversation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IconArrowForward } from "../Shared/SVG/Icons";
import { IconArrowForward, IconRefresh, IconReply } from "../Shared/SVG/Icons";

import { styled } from "@/stitches.config";
import { transform } from "next/dist/build/swc";
import { useRef } from "react";
Expand Down Expand Up @@ -52,8 +53,9 @@ const ChatConversation: React.FC<ChatConversationProps> = ({
"dc-search",
) as HTMLTextAreaElement;
if (textarea) {
textarea.focus();
textarea.value = "";
textarea.innerText = "";
textarea.focus();
}

router.push({
Expand All @@ -62,7 +64,7 @@ const ChatConversation: React.FC<ChatConversationProps> = ({
};

return (
<StyledChatConversation>
<StyledChatConversation data-testid="chat-conversation">
<form onSubmit={handleSubmit} ref={formRef} data-is-focused="false">
<textarea
ref={textareaRef}
Expand All @@ -72,11 +74,12 @@ const ChatConversation: React.FC<ChatConversationProps> = ({
onBlur={handleFocus}
></textarea>
<button type="submit" disabled={isStreaming}>
<IconArrowForward />
Reply <IconReply />
</button>
</form>
<StyledResetButton onClick={handleClearConversation}>
Clear Conversation
Start new Conversation
<IconRefresh />
</StyledResetButton>
</StyledChatConversation>
);
Expand All @@ -85,6 +88,10 @@ const ChatConversation: React.FC<ChatConversationProps> = ({
const StyledResetButton = styled("button", {
border: "none",
backgroundColor: "$white",
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
gap: "$gr1",
fontFamily: "$northwesternSansRegular",
fontSize: "$gr3",
color: "$purple",
Expand All @@ -96,6 +103,16 @@ const StyledResetButton = styled("button", {
textDecorationThickness: "min(2px,max(1px,.05em))",
textUnderlineOffset: "calc(.05em + 2px)",
textDecorationColor: "$purple10",
margin: "0 auto",

svg: {
fill: "transparent",
stroke: "$purple",
strokeWidth: "48px",
height: "1.25em",
width: "1.25em",
transform: "rotate(45deg) scaleX(-1)",
},
});

const StyledChatConversation = styled("div", {
Expand Down Expand Up @@ -166,29 +183,34 @@ const StyledChatConversation = styled("div", {
bottom: "$gr2",
right: "$gr2",
height: "38px",
width: "38px",
borderRadius: "3px",
background: "$purple60",
background: "$purple",
border: "none",
color: "$white",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "$dcAll",
cursor: "pointer",
fontSize: "$gr2",
padding: "0 $gr2",
gap: "$gr2",
fontFamily: "$northwesternSansRegular",

"&:hover, &:focus": {
backgroundColor: "$purple",
backgroundColor: "$purple120",
color: "$white",
},

svg: {
width: "1.15rem",
height: "1.15rem",
transform: "rotate(-90deg)",
width: "1rem",
height: "1rem",
fill: "transparent",
stroke: "$white",
// transform: "rotate(-90deg)",

path: {
strokeWidth: "60px",
strokeWidth: "32px",
},
},

Expand Down
17 changes: 9 additions & 8 deletions components/Chat/Response/Interstitial.styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const gradientAnimation = keyframes({

const StyledInterstitialIcon = styled("div", {
display: "flex",
width: "0.75rem",
height: "0.75rem",
width: "1rem",
height: "1rem",
alignItems: "center",
justifyContent: "center",
borderRadius: "50%",
Expand All @@ -30,21 +30,21 @@ const StyledInterstitialIcon = styled("div", {

svg: {
fill: "$purple",
width: "0.75rem",
height: "0.75rem",
width: "1rem",
height: "1rem",
},
});

const StyledInterstitial = styled("div", {
fontFamily: "$northwesternSansRegular",
fontWeight: "400",
fontSize: "$gr2",
fontSize: "$gr3",
display: "inline-flex",
alignItems: "center",
gap: "$gr1",
// marginLeft: "calc(-1.5rem - $gr2)",
gap: "$gr2",
marginBottom: "$gr1",
width: "fit-content",
color: "$purple120",
color: "$purple60",
borderRadius: "1em",
paddingRight: "$gr2",
backgroundSize: "250%",
Expand All @@ -54,6 +54,7 @@ const StyledInterstitial = styled("div", {
strong: {
fontFamily: "$northwesternSansBold",
fontWeight: "400",
color: "$purple",
},
});

Expand Down
16 changes: 13 additions & 3 deletions components/Chat/Response/Markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React from "react";
import { StyledResponseMarkdown } from "@/components/Chat/Response/Response.styled";
import useMarkdown from "@nulib/use-markdown";

const ResponseMarkdown = ({ content }: { content: string }) => {
const { html } = useMarkdown(content);

/**
* Add a wrapper around HTML table elements to allow
* for horizontal scrolling in responsive viewports
*/
function addTableWrapper(html: string) {
let parsedHtml = html;

const tableRegex = /<table>(.*?)<\/table>/gs;
Expand All @@ -17,6 +19,14 @@ const ResponseMarkdown = ({ content }: { content: string }) => {
});
}

return parsedHtml;
}

const ResponseMarkdown = ({ content }: { content: string }) => {
const { html } = useMarkdown(content);

const parsedHtml = addTableWrapper(html);

return (
<StyledResponseMarkdown dangerouslySetInnerHTML={{ __html: parsedHtml }} />
);
Expand Down
20 changes: 13 additions & 7 deletions components/Chat/Response/Response.styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ const StyledResponse = styled("article", {
flexDirection: "column",
gap: "$gr3",
zIndex: "0",
marginBottom: "$gr4",
marginBottom: "$gr5",

"> div": {
display: "flex",
flexDirection: "column",
gap: "$gr3",
},

"h1, h2, h3, h4, h5, h6, strong": {
fontFamily: "$northwesternSansBold",
Expand Down Expand Up @@ -52,10 +58,6 @@ const StyledImages = styled("div", {
figure: {
padding: "0",

"> div": {
boxShadow: "5px 5px 13px rgba(0, 0, 0, 0.25)",
},

figcaption: {
"span:first-of-type": {
textOverflow: "ellipsis",
Expand All @@ -69,7 +71,7 @@ const StyledImages = styled("div", {
},
});

const StyledQuestion = styled("h3", {
const StyledQuestion = styled("header", {
fontFamily: "$northwesternSansBold",
fontWeight: "400",
fontSize: "$gr3",
Expand All @@ -93,10 +95,14 @@ const StyledResponseMarkdown = styled("div", {
margin: "$gr4 0",
},

p: {
"p, li": {
lineHeight: "inherit",
},

li: {
marginBottom: "$gr1",
},

"h1, h2, h3, h4, h5, h6, strong": {
fontWeight: "400",
fontFamily: "$northwesternSansBold",
Expand Down
12 changes: 9 additions & 3 deletions components/Chat/Response/Response.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const ChatResponse: React.FC<ChatResponseProps> = ({
const [streamedMessage, setStreamedMessage] = useState<string>("");
const [isStreamingComplete, setIsStreamingComplete] = useState(false);

useEffect(() => {
setIsStreamingComplete(false);
}, [conversationRef, question]);

useEffect(() => {
console.log(`message`, message);

Expand Down Expand Up @@ -123,9 +127,11 @@ const ChatResponse: React.FC<ChatResponseProps> = ({
return (
<StyledResponse>
<StyledQuestion>{question}</StyledQuestion>
{renderedMessage}
{streamedMessage && <ResponseMarkdown content={streamedMessage} />}
{!isStreamingComplete && <BouncingLoader />}
<div>
{renderedMessage}
{streamedMessage && <ResponseMarkdown content={streamedMessage} />}
{!isStreamingComplete && <BouncingLoader />}
</div>
</StyledResponse>
);
};
Expand Down
11 changes: 7 additions & 4 deletions components/Search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ const Search: React.FC<SearchProps> = ({ isSearchActive }) => {
const router = useRouter();
const { urlFacets } = useQueryParams();

const { q } = router.query;

const { isChecked } = useGenerativeAISearchToggle();

const searchRef = useRef<HTMLTextAreaElement>(null);
const formRef = useRef<HTMLFormElement>(null);

const [isLoaded, setIsLoaded] = useState<boolean>(false);
const [searchValue, setSearchValue] = useState<string>("");
const [searchValue, setSearchValue] = useState<string>(q as string);
const [searchFocus, setSearchFocus] = useState<boolean>(false);

const appendSearchJumpTo = isCollectionPage(router?.pathname);
Expand Down Expand Up @@ -88,12 +90,13 @@ const Search: React.FC<SearchProps> = ({ isSearchActive }) => {
useEffect(() => setIsLoaded(true), []);

useEffect(() => {
if (router) {
const { q } = router.query;
if (q) {
if (q && searchRef.current) searchRef.current.value = q as string;
setSearchValue(q as string);
} else {
setSearchValue("");
}
}, [router]);
}, [q]);

useEffect(() => {
!searchFocus && !searchValue ? isSearchActive(false) : isSearchActive(true);
Expand Down
Loading

0 comments on commit c6fa6c0

Please sign in to comment.