How did you learn web development?

Correct! But it’s just staging your changes (since it’s just git add)

I add all the changes I want in a commit, then I call git commit -m after I’ve finished all the git add -p prompts.

No need for ctrl+c - q will break you out. And ? to get explanation of the letters!

(1/1) Stage this hunk [y,n,q,a,d,e,?]? ?
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
e - manually edit the current hunk
? - print help

Real Codaz

Ub3r H4ckz0r

I just want to chime in, that this is not the only reason to use CLI! (though it’s a nice benefit hehe)

The reasons I use CLI for many things, over a GUI option:

  • CLI is usually supported in more places.
    • Like if I’m ssh-ing into a server, there may not be any display system at all!
    • Windows/Macs/other OS issues more common w/ GUI
  • CLI tend to be more mature and stable - nobody is going to change the names of git add/git commit, but they may move around the “Commit” button in the GUI
  • CLI is usually more feature rich. Adding features to a GUI app takes more work and needs to worry a bit more about the “OGS Cockpit” issue
  • For Git, at least, the CLI is the common denominator, so you’ll get more support when you Google “how do I do X in git” vs. “how do I do X in SomeGitGUI”
    • Caveat: usually it’s more intuitive “how to do X” in GUI, so there’s a tradeoff
  • Easier to share reproducible commands
    • Can be useful for sharing tips on forums (with GUI you might need to take a screenshot and add highlighting in a photo editor)
    • Also can automate things w/ bash scripts
4 Likes

The standard programming term :stuck_out_tongue:

5 Likes

There may not enough people reading raw SGF to merit a style guide, but I think it does make sense to use white space to logically group things, and the way you’ve done it looks nice.

Sort of related - for software it’s common for a formatting tool be the style guide (at least for simple things like whitespace). For example, OGS uses Prettier in some repos. There are Black or Ruff for Python, gofmt for Go, etc. Would be pretty cool to have a SGF formatter!

1 Like

How do you test UI features? i.e. I click on the goban, and a stone appears

3 Likes

There are frameworks to test UIs. Selenium is a big one for the kind of e2e test you described.

Halp LLM

How do you test UI features? i.e. I click on the goban, and a stone appears
Write me a test in selenium that does this.

To test UI features like clicking on a goban (a board used in the game of Go) and having a stone appear, you can use Selenium, a popular tool for automating web browsers. Below is an example of how you might write a test in Python using Selenium to perform this action:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time

# Set up the WebDriver (make sure to have the appropriate driver installed, e.g., chromedriver)
driver = webdriver.Chrome()

try:
    # Navigate to the page with the goban
    driver.get("URL_OF_YOUR_GOBAN_PAGE")

    # Locate the goban element (replace 'goban_selector' with the actual selector for the goban)
    goban = driver.find_element(By.CSS_SELECTOR, "goban_selector")

    # Perform a click action on the goban
    actions = ActionChains(driver)
    actions.click(goban).perform()

    # Wait for a short period to allow the stone to appear
    time.sleep(2)

    # Verify that the stone has appeared (replace 'stone_selector' with the actual selector for the stone)
    stone = driver.find_element(By.CSS_SELECTOR, "stone_selector")
    assert stone.is_displayed(), "The stone did not appear on the goban."

finally:
    # Close the browser
    driver.quit()

Key Points:

  • WebDriver Setup: Ensure you have the appropriate WebDriver installed (e.g., chromedriver for Chrome) and that it’s in your system’s PATH.
  • Selectors: Replace "goban_selector" and "stone_selector" with the actual CSS selectors or XPath expressions that identify the goban and stone elements on your page.
  • Action Chains: Used to perform complex user interactions like clicking.
  • Assertions: Check if the stone is displayed after the click action to verify the test’s success.
  • Cleanup: Always close the browser with driver.quit() to free up resources.

Make sure to adjust the selectors and URL to match your specific application’s HTML structure.

But for the “demonstrate a bug”/TDD use-case, unit tests are better. There are a lot of testing frameworks that look similar, but can simulate browser elements and can run faster than an e2e test.

Halp LLM

Great for e2e! Can you recommend a similar test for unit tests? You can use a different framework

For unit testing UI components, you typically want to isolate the component logic from the actual browser environment. This is often done using a JavaScript testing framework like Jest along with a testing utility like React Testing Library if you’re working with React, or similar tools for other frameworks.

Here’s an example of how you might write a unit test for a React component that represents a goban, using Jest and React Testing Library:

React Component Example

Let’s assume you have a simple React component for the goban:

// Goban.js
import React, { useState } from 'react';

const Goban = () => {
  const [stone, setStone] = useState(false);

  const handleClick = () => {
    setStone(true);
  };

  return (
    <div data-testid="goban" onClick={handleClick} style={{ width: '200px', height: '200px', border: '1px solid black' }}>
      {stone && <div data-testid="stone" style={{ width: '20px', height: '20px', backgroundColor: 'black' }}></div>}
    </div>
  );
};

export default Goban;

Unit Test Example

Here’s how you might write a unit test for this component:

// Goban.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import Goban from './Goban';

test('clicking on the goban places a stone', () => {
  // Render the Goban component
  const { getByTestId, queryByTestId } = render(<Goban />);

  // Get the goban element
  const goban = getByTestId('goban');

  // Ensure the stone is not present initially
  expect(queryByTestId('stone')).toBeNull();

  // Simulate a click on the goban
  fireEvent.click(goban);

  // Verify that the stone appears
  expect(getByTestId('stone')).toBeInTheDocument();
});

Key Points:

  • React Testing Library: This library is used to render components and simulate user interactions in a way that closely resembles how users interact with your app.
  • Jest: A popular testing framework for JavaScript, often used with React.
  • fireEvent: Used to simulate events like clicks.
  • Assertions: Use Jest’s expect function to assert that the stone appears after the goban is clicked.
  • data-testid: A common pattern for selecting elements in tests without relying on CSS classes or IDs that might change.

This approach allows you to test the component’s behavior in isolation, ensuring that the logic for placing a stone works as expected without needing to run a full end-to-end test.

That’s still a little painful as it’s tied to the UI framework. Testing can actually help you improve your architecture by splitting stuff into into “View” and “Business logic”. So you might just write unit tests that test your GobanController (with no DOM/UI commands).

Halp LLM

Okay let’s ignore the UI for now. How would you test the underlying model/controller using Jest?

If you’re working with a model or controller in a JavaScript application and want to test it using Jest, you can focus on testing the core logic and functionality of these components. Let’s assume you have a simple model or controller that handles the logic for placing a stone on a goban.

Example Model/Controller

Here’s a basic example of a JavaScript class that represents the logic for placing a stone on a goban:

// gobanController.js
class GobanController {
  constructor() {
    this.stonePlaced = false;
  }

  placeStone() {
    this.stonePlaced = true;
    return "Stone placed on the goban.";
  }

  isStonePlaced() {
    return this.stonePlaced;
  }
}

module.exports = GobanController;

Unit Test Example

Here’s how you might write a unit test for this model/controller using Jest:

// gobanController.test.js
const GobanController = require('./gobanController');

describe('GobanController', () => {
  let gobanController;

  beforeEach(() => {
    gobanController = new GobanController();
  });

  test('should not have a stone placed initially', () => {
    expect(gobanController.isStonePlaced()).toBe(false);
  });

  test('should place a stone on the goban', () => {
    const result = gobanController.placeStone();
    expect(gobanController.isStonePlaced()).toBe(true);
    expect(result).toBe("Stone placed on the goban.");
  });
});

Key Points:

  • Jest Framework: A popular testing framework for JavaScript, providing a simple API for writing tests.
  • describe Block: Used to group related tests together.
  • beforeEach Hook: Sets up a fresh instance of GobanController before each test to ensure isolation.
  • Test Cases: Use test or it to define individual test cases.
  • Assertions: Use Jest’s expect function to assert expected outcomes, such as checking the state of stonePlaced and the return value of placeStone.

This approach allows you to test the core logic of your model or controller, ensuring that the functionality works as expected without involving any UI components.


But this is another reason why CLIs rule - it’s much easier to test text IO than to test browser GUI elements :smile:

5 Likes

I’m a big fan of TDD though not the best practitioner.

Lately I’ve been more and more coming to the conclusion that it’s not so much about finding bugs as it is about forcing beneficial changes in your coding style.

Defining what you are going to implement ahead of time, dividing the problem into small chunks of work, splitting up complicated functions, limiting use of conditional expressions, emphasizing predictable, readable code, injecting dependencies, etc.

Oh, and the “maintenance” part means you can actually maintain code, for example to improve it in these directions. Whereas without testing there are always huge messes that you are afraid to touch.

All of that comes naturally out of a TDD practice.

6 Likes

I made it so the board updates in real-time as the text is edited, which means you can type a game by hand pretty easily, which is maybe silly but kinda neat to me. I think if I add some kind of autocomplete, it will actually be really easy and effective! I recorded a short demo here: kosumi1.0demo01.mp4 - Google Drive

Adding in a massive block of stones with AW or AB is much easier by just typing the start and end coordinates rather than by clicking for each stone (as demonstrated in the video) which made me think that it would be a cool option to have a tool where you can select an area with click+drag and automatically fill that area with stones, for setting up a position

Anyways i guess i should be learning about unit tests now :joy:

i’m guessing the favorite js unit testing framework here is Jest?

8 Likes

For me, yeah, but mainly because it’s what I know. I don’t think you’ll have a bad time if you use one of the other top frameworks, and they all work similarly.

For a bit of context for why I chose it when I started adding OGS tests way back when:

2 Likes

I realized something else while demonstrating TDD to someone yesterday.

With normal development you are constantly context-switching between typing code and using your program. While in TDD you just keep typing, glancing occasionally at the test results in another text window. So you can be in this single code-obsessed mode the whole time you are developing a new feature. Feels very efficient.

I don’t know these JS testing frameworks at all, but coming from the Ruby on Rails world, the RSpec/Capybara/Selenium stack is so cool. You get to write stuff like this:

create(:user, email: email, password: password)
visit sign_in_path
expect(page).to have_css('h2', text: 'Log in')
fill_in('Email', with: email)
fill_in('Password', with: password)
click_button 'Log in'
expect(page).to have_text 'Signed in successfully'
8 Likes

This isn’t code, this is just English :rofl:

6 Likes

One thing to watch out for: unit tests are different to application tests such as those shown above.

They both have their place … it’s helpful to know which is which.

In the current context, a unit test would test some element of the parser chain (as a standalone unit), wheras an application test would check if you’re seeing what you expect in the GUI.

6 Likes

I would be interested to learn about it.

4 Likes

Its working name is ‘super tic-tac-Go’, based on the mechanics of ‘Super tic-tac-toe’, which is played on a 9x9 grid consisting of 9 3x3 grids:

Each move you place on a 3x3 grid dictates which one of the nine 3x3 grids (nonant? enneant?) the next player may play in. So if, for example, I play in the top-left corner of the lower-right nonant, you’d next play anywhere in the upper-left nonant.

Some friends and I developed the Go version of this while we were living at Devin’s Baduk House in Ohio, and in our playtesting, determined that self-capture should be allowed, and passing stones should be required. You can pass anytime, but this allows your opponent to play in any nonant. The 3x3 boards are all connected, so a single chain can share liberties between multiple nonants.

You can see two examples of games that I played here on OGS: one with self-capture allowed, and one without.

It’s possible for ko to happen, but it’s so incredibly rare that I don’t think it’s even necessary to have a ko rule. I’d like to do substantially more playtesting to determine the optimal ruleset; also, it may require additional restrictions for the first few moves, as it’s possible for the second player to force the first player to play their first 9 moves in the same nonant. I’m not entirely sure this is an optimal strategy for the second player, though, so it might not matter.

9 Likes

I’m finally getting around to figuring out jest!! I haven’t been sharing updates here out of shame for not yet having done the thing i said i was gonna do… but i’m on it now :joy:

Buuuuuut now that I’ve installed Jest, i have questions. I’m scared to git push because after i installed Jest, a .\node_modules\ with nearly 200 subdirectories appeared in my project directory, as well as package-lock.json and package.json.

When I git push, will all of these also be pushed to github? Is that a desirable behavior? Should I git ignore some of this or something?

Any insight here would be welcome and much appreciated!!

Kosumi:0.1.0 updates!

i mostly updated the UI a bunch, changed how the text editor works and how the different elements react to each other, so everything is much faster and more responsive now. I also added a listener to the goban display that checks what intersection you’re clicking on. It doesn’t do anything yet, but adding in graphic editing should be relatively simple in the future.


A sharp eye might notice that --INSERT-- at the bottom of the text editor and have an idea of what I’m planning to do next… :innocent:

6 Likes

Oh, also, when testing a function, should I import the function from the program into the test? Or copy the function into a new .js file? I’m a little confused as to how to structure this.

Or, in general, should every function be its own file? :face_with_monocle:

3 Likes

As I understand it:

  • package.json defines the packages your project depends on, including their version. In this case jest, I suppose. If you want to add a package, you can do it here. It’s good to push this file to your upstream repo.
  • package-lock.json: I’m less sure about this one. It’s an auto-generated file and I guess this includes not only the packages you directly use, but also those packages’ dependencies and so on. I think this file should not be pushed, although it wouldn’t do harm.
  • The node modules directory: This includes compiled / transpiled stuff that come from the packages you use. This directory should be added to the gitignore, so it doesn’t get pushed to your repo.
2 Likes

Push package.json (it tells which dependencies your project has) and package-lock.json (it tells which exact versions of the dependencies and their dependencies you are using). Git-ignire node-modules (it’s huge and package.json and package-lock.json provide all necessary data).

Don’t copy paste your code for testing, you want to test the real code (import it), not the copied one.

Don’t put each function in a separate file, group them as it makes sense.

5 Likes

You’ve stepped on one of the big in-jokes in the node community :grin:

Screenshot_20241117_190214-1

I agree with @martin3141 and @Jon_Ko just gitignore node_modules, but check in the package files. If it helps, here’s a (very broad) .gitignore for node projects: gitignore/Node.gitignore at main · github/gitignore · GitHub

7 Likes

So is package.json automatically generated? I see this in tons of repos, and was wondering if I need to generate it myself.

I’m thinking I might try to get comfortable with some of these tools / best practices by cleaning up an old spaghetti code project. Is it okay to post questions here about that generally, if it has nothing to do with Go?

3 Likes

You can generate (and edit) package.json manually or automatically (to an extent). It’s used for NodeJS projects with npm or yarn and maybe more.

3 Likes