npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wdio-locator-scout-service

v0.3.0

Published

A WebdriverIO service that automatically generates UI locator candidates for Android and iOS apps.

Readme

WebdriverIO Locator Scout Service (v0.3.0)

NPM version

A WebdriverIO service that automatically generates a helpful report of UI locator candidates for your Android and iOS app. Stop wasting time in Appium Inspector and let the scout find the best selectors for you!

Why use Locator Scout?

  • Cross-Platform Support: Works seamlessly for both Android and iOS with automatic platform detection.
  • Save Time: No more manual digging through XML or UI hierarchies in Appium Inspector.
  • Best Practices: Automatically scores and prioritizes selectors based on industry best practices (resource-id / name > content-desc / label).
  • Easy Debugging: Get a clear snapshot of the UI structure of any screen in your app.

Installation

npm install wdio-locator-scout-service --save-dev

Configuration

Add the plugin to your wdio.conf.js services list. This will automatically add the browser.dumpLocators() command to your test environment.

// wdio.conf.js
export const config = {
  // ...
  services: [
    // ... other services
    "locator-scout",
  ],
  // ...
};

Usage

Once configured, the dumpLocators command is available on the browser object in your tests. The plugin automatically detects the platform (Android or iOS) and generates the appropriate report.

import OnboardingPage from "../../pageobjects/OnboardingPage";

describe("[Locator Scout] 로케이터 확인", async () => {
  const platformName = await browser.capabilities.platformName;

  it(`${platformName} 온보딩 화면 로케이터 확인`, async () => {
    await browser.dumpLocators({
      fileName: "onboarding_main_screen",
      reportTitle: `${platformName} 온보딩 화면 로케이터 확인`,
      outDir: "./reports/locator/onboarding_main_screen",
    });
  });

  it(`${platformName} 시작 화면 로케이터 확인`, async () => {
    await OnboardingPage.clickCheckAgreementButton();
    await OnboardingPage.clickStartButton();

    await browser.dumpLocators({
      fileName: "start_main_screen",
      reportTitle: `${platformName} 시작 화면 로케이터 확인`,
      outDir: "./reports/locator/start_main_screen",
    });
  });
});

Example Reports

See how Locator Scout provides optimized reports tailored for each platform.

  • Device: ANDROID R3CN30JZMZX 13
  • Scanned Elements: 12
  • Generated: 11/28/2025, 3:03:52 PM

    Note: ⚠️ indicates a shared ID (not unique).

1. Overview (Top Elements)

| # | Score | Context (Description) | Class | ID (Resource) | Content-Desc | Text | | --- | ----: | -------------------------------------------------------------------------- | -------- | ------------- | ------------------------------------- | ---------------------------------------------------------------------- | | 1 | 33 | 수면무호흡 진단 보조앱 Apnotrack | TextView | - | onboarding_title | 수면무호흡 진단 보조앱 Apnotrack | | 2 | 33 | 아래 내용을 이해합니다 | TextView | - | onboarding_agreement_text | 아래 내용을 이해합니다 | | 3 | 33 | 이 제품은 의료기기입니다 | TextView | - | onboarding_medical_device_title | 이 제품은 의료기기입니다 | | 4 | 33 | 이 애플리케이션은 의료기기입니다. 의료기기 라벨을 확인할 수 있습니다.. | TextView | - | onboarding_medical_device_description | 이 애플리케이션은 의료기기입니다. 의료기기 라벨을 확인할 수 있습니다.. | | 5 | 33 | 시작하기 | TextView | - | onboarding_done_text | 시작하기 | | 6 | 26 | onboarding_agreement_checkbox | CheckBox | - | onboarding_agreement_checkbox | - | | 7 | 21 | onboarding_done_button | View | - | onboarding_done_button | - | | 8 | 13 | 1 | TextView | - | - | 1 | | 9 | 13 | 사용자 연령은 20세 이상입니다 | TextView | - | - | 사용자 연령은 20세 이상입니다 | | 10 | 13 | 이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다. | TextView | - | - | 이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다. | | 11 | 13 | 2 | TextView | - | - | 2 | | 12 | 1 | (view: Button) | Button | - | - | - |

2. Selector Proposals

1. [수면무호흡 진단 보조앱 Apnotrack] (Score: 33)

  • Accessibility ID: ~onboarding_title
  • XPath (Text): //*[@text="수면무호흡 진단 보조앱
Apnotrack"]
  • XPath (Class+Text): //android.widget.TextView[@text="수면무호흡 진단 보조앱
Apnotrack"]

2. [아래 내용을 이해합니다] (Score: 33)

  • Accessibility ID: ~onboarding_agreement_text
  • XPath (Text): //*[@text="아래 내용을 이해합니다"]
  • XPath (Class+Text): //android.widget.TextView[@text="아래 내용을 이해합니다"]

3. [이 제품은 의료기기입니다] (Score: 33)

  • Accessibility ID: ~onboarding_medical_device_title
  • XPath (Text): //*[@text="이 제품은 의료기기입니다"]
  • XPath (Class+Text): //android.widget.TextView[@text="이 제품은 의료기기입니다"]

4. [이 애플리케이션은 의료기기입니다. 의료기기 라벨을 확인할 수 있습니다..] (Score: 33)

  • Accessibility ID: ~onboarding_medical_device_description
  • XPath (Text): //*[@text="이 애플리케이션은 의료기기입니다. 의료기기 라벨을 확인할 수 있습니다.."]
  • XPath (Class+Text): //android.widget.TextView[@text="이 애플리케이션은 의료기기입니다. 의료기기 라벨을 확인할 수 있습니다.."]

5. [시작하기] (Score: 33)

  • Accessibility ID: ~onboarding_done_text
  • XPath (Text): //*[@text="시작하기"]
  • XPath (Class+Text): //android.widget.TextView[@text="시작하기"]

6. [onboarding_agreement_checkbox] (Score: 26)

  • Accessibility ID: ~onboarding_agreement_checkbox

7. [onboarding_done_button] (Score: 21)

  • Accessibility ID: ~onboarding_done_button

8. [1] (Score: 13)

  • XPath (Text): //*[@text="1"]
  • XPath (Class+Text): //android.widget.TextView[@text="1"]

9. [사용자 연령은 20세 이상입니다] (Score: 13)

  • XPath (Text): //*[@text="사용자 연령은 20세 이상입니다"]
  • XPath (Class+Text): //android.widget.TextView[@text="사용자 연령은 20세 이상입니다"]

10. [이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다.] (Score: 13)

  • XPath (Text): //*[@text="이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다."]
  • XPath (Class+Text): //android.widget.TextView[@text="이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다."]

11. [2] (Score: 13)

  • XPath (Text): //*[@text="2"]
  • XPath (Class+Text): //android.widget.TextView[@text="2"]

12. [(view: Button)] (Score: 1)

  • XPath (Class): //android.widget.Button
  • Device: IOS 아이폰 12 | 18.7.2 18.7
  • Scanned Elements: 12
  • Generated: 11/28/2025, 3:04:06 PM

    Note: ⚠️ indicates a shared ID (not unique).

1. Overview (Top Elements)

| # | Score | Context (Description) | Type | Name (ID) | Label | Value | | --- | ----: | ---------------------------------------------------------------- | ---------- | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | 1 | 31 | uncheck | Image | onboarding_agreement_checkbox | uncheck | - | | 2 | 31 | 아래 내용을 이해합니다 | StaticText | onboarding_agreement_text | 아래 내용을 이해합니다 | 아래 내용을 이해합니다 | | 3 | 17 | 시작하기 | Button | onboarding_container ⚠️ | 시작하기 | - | | 4 | 13 | 수면무호흡 진단 보조앱 | StaticText | onboarding_container ⚠️ | 수면무호흡 진단 보조앱 | 수면무호흡 진단 보조앱 | | 5 | 13 | Apnotrack | StaticText | onboarding_container ⚠️ | Apnotrack | Apnotrack | | 6 | 13 | 1 | StaticText | onboarding_container ⚠️ | 1 | 1 | | 7 | 13 | 사용자 연령은 20세 이상입니다 | StaticText | onboarding_container ⚠️ | 사용자 연령은 20세 이상입니다 | 사용자 연령은 20세 이상입니다 | | 8 | 13 | 이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다. | StaticText | onboarding_container ⚠️ | 이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다. | 이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다. | | 9 | 13 | 2 | StaticText | onboarding_container ⚠️ | 2 | 2 | | 10 | 13 | 이 제품은 의료기기입니다 | StaticText | onboarding_container ⚠️ | 이 제품은 의료기기입니다 | 이 제품은 의료기기입니다 | | 11 | 13 | 이 애플리케이션은 의료기기 입니다. | StaticText | onboarding_container ⚠️ | 이 애플리케이션은 의료기기 입니다. | 이 애플리케이션은 의료기기 입니다. | | 12 | 13 | 의료기기 라벨을 확인할 수 있습니다. | StaticText | onboarding_container ⚠️ | 의료기기 라벨을 확인할 수 있습니다. | 의료기기 라벨을 확인할 수 있습니다. |

2. Selector Proposals

1. [uncheck] (Score: 31)

  • Accessibility ID: ~onboarding_agreement_checkbox
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeImage[label == "uncheck"]
  • Predicate (Label): -ios predicate string:label == "uncheck"
  • XPath (Label): //XCUIElementTypeImage[@label="uncheck"]

2. [아래 내용을 이해합니다] (Score: 31)

  • Accessibility ID: ~onboarding_agreement_text
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "아래 내용을 이해합니다"]
  • Predicate (Label): -ios predicate string:label == "아래 내용을 이해합니다"
  • XPath (Label): //XCUIElementTypeStaticText[@label="아래 내용을 이해합니다"]

3. [시작하기] (Score: 17)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeButton[label == "시작하기"]
  • Predicate (Label): -ios predicate string:label == "시작하기"
  • XPath (Label): //XCUIElementTypeButton[@label="시작하기"]

4. [수면무호흡 진단 보조앱] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "수면무호흡 진단 보조앱"]
  • Predicate (Label): -ios predicate string:label == "수면무호흡 진단 보조앱"
  • XPath (Label): //XCUIElementTypeStaticText[@label="수면무호흡 진단 보조앱"]

5. [Apnotrack] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "Apnotrack"]
  • Predicate (Label): -ios predicate string:label == "Apnotrack"
  • XPath (Label): //XCUIElementTypeStaticText[@label="Apnotrack"]

6. [1] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "1"]
  • Predicate (Label): -ios predicate string:label == "1"
  • XPath (Label): //XCUIElementTypeStaticText[@label="1"]

7. [사용자 연령은 20세 이상입니다] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "사용자 연령은 20세 이상입니다"]
  • Predicate (Label): -ios predicate string:label == "사용자 연령은 20세 이상입니다"
  • XPath (Label): //XCUIElementTypeStaticText[@label="사용자 연령은 20세 이상입니다"]

8. [이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다.] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "이 제품은 20세 이상을 대상으로 사용되도록 되어 있습니다."]
  • Predicate (Label): -ios predicate string:label == "이 제품은 20세 이상을 대상으로 사용되도록
되어 있습니다."
  • XPath (Label): //XCUIElementTypeStaticText[@label="이 제품은 20세 이상을 대상으로 사용되도록
되어 있습니다."]

9. [2] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "2"]
  • Predicate (Label): -ios predicate string:label == "2"
  • XPath (Label): //XCUIElementTypeStaticText[@label="2"]

10. [이 제품은 의료기기입니다] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "이 제품은 의료기기입니다"]
  • Predicate (Label): -ios predicate string:label == "이 제품은 의료기기입니다"
  • XPath (Label): //XCUIElementTypeStaticText[@label="이 제품은 의료기기입니다"]

11. [이 애플리케이션은 의료기기 입니다.] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "이 애플리케이션은 의료기기 입니다."]
  • Predicate (Label): -ios predicate string:label == "이 애플리케이션은 의료기기 입니다."
  • XPath (Label): //XCUIElementTypeStaticText[@label="이 애플리케이션은 의료기기 입니다."]

12. [의료기기 라벨을 확인할 수 있습니다.] (Score: 13)

  • Accessibility ID: ~onboarding_container (Shared ID - caution)
  • Class Chain (Label): -ios class chain:**/XCUIElementTypeStaticText[label == "의료기기 라벨을 확인할 수 있습니다."]
  • Predicate (Label): -ios predicate string:label == "의료기기 라벨을 확인할 수 있습니다."
  • XPath (Label): //XCUIElementTypeStaticText[@label="의료기기 라벨을 확인할 수 있습니다."]

Command Options

You can pass an options object to browser.dumpLocators() to customize its behavior.

| Option | Type | Default | Description | | :--------------- | :------- | :------------------------------------------------------ | :----------------------------------------------------------------------------------- | | outDir | string | './test/reports/locators' | Directory to save reports. | | fileName | string | 'locator-report' | Prefix for the report file name. A timestamp is appended. | | reportTitle | string | 'Platform-dependent ('... (Android)' or '... (iOS)')' | The main title inside the markdown report. If not provided, a default title is used. | | limit | number | 60 | Maximum number of UI elements to include in the report. | | stabilizeTries | number | 6 | How many times to check if the UI source has stabilized before analysis. |

Author

Jio (Lee Jiwon)

License

MIT