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: In-browser element inspector for browser recording #502

Open
wants to merge 6 commits into
base: wip/browser-recording
Choose a base branch
from

Conversation

allansson
Copy link
Collaborator

@allansson allansson commented Feb 20, 2025

Description

This PR adds support for inspecting DOM elements and their selectors while recording.

  • It adds a toolbar control to the recorded page.
  • You can select a tool to hover elements and see their selectors.
  • You can highlight elements by hovering a selector in k6 Studio.
  • You can navigate to different pages by clicking links in navigation events in k6 Studio.

How to Test

  1. Start a recording.
  2. Interact with a page.
  3. Pick the Inspect tool in the toolbar.
  4. Hover various elements to see their selectors.
  5. Hover a selector in the browser event log and check that the element is highlighted.
  6. Click a navigation event link and check that the browser navigates to that page.

Checklist

  • I have performed a self-review of my code.
  • I have added tests for my changes.
  • I have run linter locally (npm run lint) and all checks pass.
  • I have run tests locally (npm test) and all tests pass.
  • I have commented on my code, particularly in hard-to-understand areas.

Screenshots (if appropriate):

Screen.Recording.2025-02-19.at.13.44.09.mov

Related PR(s)/Issue(s)

@allansson allansson force-pushed the feat/in-browser-ui-while-recording branch from 5685cdd to 3ba756c Compare February 24, 2025 13:13
Copy link
Collaborator Author

@allansson allansson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review

selectTool: (tool: Tool | null) => void
}

export const useInBrowserUIStore = create<InBrowserUIStore>((set) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to record events if the user is using some tool, so we need some way of accessing the react state from the outside. I would've preferred to use jotai because it's much simpler, but I also didn't want to pull in another dependency. So zustand it is.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was split up into individual files. Pretty much every new file in the BrowserEventLog is just a component extracted as-is from this file. The notable exceptions are the Selector and PageNavigationDescription components.

children: ReactNode
}

export function RecordingContext({
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this context to keep track off whether we are in the recorder view or not. It's currently used to enable/disable interactivity in the Selector and PageNavigationDescription components. Since the value is constant, it will never trigger any re-renders.

Comment on lines +10 to +22
const isRecording = useIsRecording()

const handleMouseEnter = () => {
if (isRecording) {
window.studio.browserRemote.highlightElement(selector)
}
}

const handleMouseLeave = () => {
if (isRecording) {
window.studio.browserRemote.highlightElement(null)
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic has been added since the component was split from BrowserEventLog.

Comment on lines +12 to +44
const Navigation = forwardRef<HTMLElement, NavigationProps>(function Navigation(
{ url },
ref
) {
const isRecording = useIsRecording()

const handleClick = (ev: MouseEvent<HTMLAnchorElement>) => {
ev.preventDefault()

window.studio.browserRemote.navigateTo(url)
}

const element = <Strong ref={ref}>{url}</Strong>

if (!isRecording) {
return element
}

return (
<Link
css={css`
cursor: pointer;

&:hover {
text-decoration: underline;
}
`}
onClick={handleClick}
>
{element}
</Link>
)
})
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic has been added since it was split from BrowserEventLog.

Comment on lines +89 to +90
"@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot use @radix-ui/theme in the browser extension. We are using a shadow DOM to isolate our styling from the recorded page, but the <Theme /> component mounts its styles in document.head. This means that the theme styles are applied to the recorded page, and not to our shadow DOM. As far as I can tell, there's no way of specifying where the styles should be mounted.

@@ -73,6 +73,7 @@
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/modifiers": "^7.0.0",
"@dnd-kit/sortable": "^8.0.0",
"@emotion/cache": "^11.14.0",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to configure emotion to inject the style elements inside our shadow root, and that requires us to configure a custom cache.

@allansson allansson marked this pull request as ready for review February 25, 2025 13:55
@allansson allansson requested a review from a team as a code owner February 25, 2025 13:55
@allansson allansson requested review from cristianoventura and e-fisher and removed request for a team February 25, 2025 13:55
Copy link
Collaborator

@e-fisher e-fisher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀
Should we drop the dot after event description, looks a bit weird with div class names?
screencapture 2025-02-26 at 10 49 52

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants